On 0.2.5e, the following message is printed to stdout whenever a cart containing any arbitrary meta section is run:
$ pico8 -run test.p8 codo_free fail 21 0 |
test.p8:
pico-8 cartridge // http://www.pico-8.com version 39 __meta:foo__ bar |
Carts seem to run fine, so there don't seem to be any other negative effects.
Hi, friends!
Here's a demo featuring 5 glorious channels of lo-fi audio! Making a chipbreak-style tune in Pico-8 has been in the back of my mind ever since @carlc27843 discovered the undocumented PCM channel, and now I can finally check this off my list! After almost 2 years! π
All the drums are samples, triggered by watching the tracker with stat(56). The samples are then fed to the PCM channel by monitoring the buffer with stat(108). I'd originally planned on building a 5-channel tracker from this demo, but I had a tough time getting the samples to sync consistently. I'm not sure if that's because of my own shortcomings, or maybe because as @zep literally said, the sync is "not perfect".
For the gfx, the star animations are also triggered by stat(56), whenever a snare sample is played. The road is just one gigantic image using a palette cycle. It looks like this:

Anyway, I had a lot of fun putting this together. I hope you like it! π
Special thanks to @pahammond for GEM, which helped keep this cart under the compressed limit!
Hi Zep! :) I think I found a bug in one of the more esoteric stat calls?
Bug:
According to the manual, stat(56) should return the number of ticks played in the current pattern. Currently (0.2.5e), it seems to poll the leftmost sfx in the pattern for the count. That makes sense bc the overall pattern length is determined by the leftmost sfx which is not a loop, but as the title says, stat(56) will reset back to 0 early if the leftmost sfx is a loop.
Expected behavior:
stat(56) should return the number of pattern ticks played regardless of looped sfx
Thanks for your time! :)
I was going to wait to post this until the weekend, but I have no self-control. π Enjoy the rest of your week, everyone!
Here's another new song! Have a great weekend! π
This one is short but sweet. I hope you enjoy it! π
One last chiptune. I hope you like it! π
One more! π
Hi everyone, I wrote this song over the weekend, I hope you like it! π
UPDATE 1/14/2023, v1.1:
This update couldn’t have happened without @thisismypassword’s contributions to the community. I recently began overhauling my build pipeline for future projects, and one of the first features I added was Shrinko8. Since Downstream Dream is my only project to use the full build pipeline, I used it for testing output from the new minifier, which led to some token golfing. Thanks to this tip, also by @thisismypassword, I was able to free up about 100 tokens! Changes include:
- Midboss section contains more action and a couple new sprites/sfx
- Rocks spawn gradually at the start of each lap (so you don’t crash into them immediately after winning the midboss section)
- Turtle hit/hurtbox size reduced
- Speed gauge colors changed to represent the danger level of being ejected
- Slight gfx adjustments
- Faster boot time
While I have your attention, I’d like to thank everyone who supported this game and said nice things about it, it means so much to me and it made my whole year! Special thanks to @extar, who recently featured it on his Pico Playtime: Best of 2022 video, and extra special thanks to @zep for featuring it on the front page on day one. It’s a huge honor to be listed among so many incredible projects from the community and I’m grateful beyond words to everyone here!
Anyway, if you liked the original release, I hope you enjoy the update!
UPDATE 06/11/2022, OST
I've added a special OST cart for the itch.io download, where you can select music from the soundtrack and watch the game play itself while you listen. I hope you enjoy it!)
Hi everyone,
Here's my new game. It's called Downstream Dream, it's a side-scroller that I guess is somewhere between kart racers and shoot-em-ups. I hope you like it!
It's also published on itch.io if you'd like to support it. Most of the content from that page is duplicated below, but first, a few thanks to BBS members:
-
To @zep, @Makke, @Felice, @Nodepond, and @pahammond for their code contributions to the community, some of which I wouldn't have been able to release this cart anytime soon without! (listed below)
-
To @freds72 and @johanp for their advice. This game would have been a lot worse if not for their kindness and willingness to help a stranger.
-
To @Liquidream for playtesting, and for lots of encouragement when I felt like giving up.
- To everyone in the Pico-8 community. I'm very grateful that so many are willing to share your creativity and kindness with others. Trading knowledge and games with you all has brought me a lot of joy.
Thank you all!
Game Controls
Legend:
β¬ οΈβ‘οΈβ¬οΈβ¬οΈ = D-Pad or Keyboard Arrow Keys
π ΎοΈ = Button 1 or Keyboard Z
β = Button 2 or Keyboard X

Movement:
β¬ οΈ + π ΎοΈ - Paddle counter-clockwise
β‘οΈ + π ΎοΈ - Paddle clockwise
β¬οΈ + π ΎοΈ - Steady ahead
β¬οΈ - Move backwards (with motor)


Offense/Defense:
β - Throw



How to Play




From the Developer

My mom loved both adventure and the American southwest; she traveled there many times over her life, and her home was filled with art and souvenirs she'd collected from her visits to the region.
When I was about seven years old, my parents rented a minivan and took me on a long roadtrip across the United States. I don’t remember a lot from that trip other than staring out the window while the landscape slowly changed from cities and farmland, to mountains, to desert, but one memory stands out from the endless monotony of the road; a stop at the Grand Canyon where my mom went white water rafting.
My dad never learned how to swim, and someone needed to watch me anyway, so the two of us waited downstream in the hot afternoon sun, looking for mom's boat to come in. I don’t think the water was particularly rough at that time of year; but like my dad, I’ve never been good at swimming either, and I spent most of the time thinking about how scary the water looked to me. I imagined how if I was on the boat with mom, I would probably fall out and be carried away by the river. She seemed very bold and brave that day!
A couple years before she left this world, mom offered to take me on a trip out west; possibly to Las Vegas, or maybe the Grand Canyon. I politely turned her down for some made-up reason, while the real one probably had something to do with still being in my 20s and wrongly believing that I was too cool to go on vacation with my mother. As a young adult, I assumed that there would always be more time with the people in my life. Now that I'm a little older, I'm learning that there is rarely ever enough. I don’t know where we might have gone or what we might have done on that trip, if I hadn't foolishly said no; but sometimes, it’s nice to dream about it.
Anyway, I hope you enjoy the game. It contains a lot of love, a little regret, and the best game I could make with Pico-8.
-ridgek
Credits and Thanks
External Libraries:
- PX9 by @zep
- Local fillp() by @Makke & @Felice
- pic2pico by @Nodepond
- GEM by Paul Hammond ( @pahammond)
- Shrinko8 by @thisismypassword
Playtesters:
- Paul Nicholas ( @Liquidream)
- John Loitermanβ (http://sbigames.comβ)
- Lex Rendon
Special Thanks To:
Hi everyone,
My new project uses massive tables of graphics metadata, so I've written a new table serializer inspired by this pull request on @BenWiley4000's pico8-table-string to get the job done. Hopefully someone else finds this useful, too!
It uses less characters to store your table as a string than pico8-table-string does (to take up less character / compressed space), but at the cost of 14 more tokens to deserialize, and possibly with less reliability. (It will break if the table contains a string a certain character sequence, see below.) You should also run the output through something like Zep's escape_binary_string before saving to code.
Supported:
- string/number/boolean values
- key/value pairs
- consecutive indexed values starting from 1
Not supported:
- 0-indexed values
- non-consecutive indexed values
- strings containing the ascii sequence
\3\120\23
Writing parsers is not one of my strengths, so pull requests on the GitHub repo are open and appreciated!
serialize
deserialize
usage
I don't feel like I have the greatest grasp on Lua metatables/metamethods, but I came across some unexpected behavior this week and was wondering if this is a bug. Example cart attached.
I'm setting up a "class" like so:
class = {} class.__index = class function class:new(instance) local instance = instance or {} setmetatable(instance, self) instance.__index = instance add(self, instance) return instance end |
To save tokens, and since I never expect to have numeric indexes in class
or any subclasses I instantiate from it, I simply add the instance to whatever object is self
when :new()
is called. ie, class[1]
is a subclass, and subclass[1] == class[1][1]
.
This works great if I use vanilla Lua ipairs()
to iterate over subclass
, but if I use Pico-8's all()
or foreach()
built-ins, things start breaking. Unlike with ipairs()
, if #subclass < #class
, the loop continues and retrieves any remaining values from class
! So, in the example below, the all()
loop will correctly access class[1][1].foo
on the first iteration, but instead of stopping, it will then try to access class[2].foo
.
EDIT: Forgot to mention, #class[1][1]
/ #subclass1
and/or count(class[1][1])
/ count(subclass1)
report the expected counts, so a C-style for loop would also work.
subclass1 = class:new() subclass2 = class:new() subclass1:new({ foo = "bar" }) -- assertion passes for _, instance in ipairs(subclass1) do assert(instance.foo) end -- assertion fails for instance in all(subclass1) do assert(instance.foo) end |
I don't mind using ipairs()
, but since it does cost an extra token, I'm hoping this is a bug!
Hi friends,
My next project is likely going to need to rotate sprites, so I've been looking at the various methods posted on the bbs. Something I'm wondering about while I've been looking at everyone's examples is, how does one approach collision detection for when a sprite is rotated?
I'm currently capable of AABB and bitmasking per row of pixels, but it seems I'm going to have to write some new methods to integrate either of these into a rotation algorithm, and I'm not sure where to start. I'd appreciate any links to any carts or non-p8 articles or anything, really!
CPU is also a concern for me, as I think I'm going to need a lot of it dedicated to drawing the backgrounds I need which would be rendered via something like spellcaster's rle library.
Thanks in advance! :)
EDIT: See the first reply below if you'd rather compile and use the native tool, which does seem more streamlined!
Ran into this on MacOS Mojave. If you put a '.' in the filename when you export binaries, the unzipped app will launch just fine, but the zipped one won't.
I made a quick video:
https://youtu.be/NZHUZV4gLGU
Hi, friends!
I've just finished my first ever video game!
I just want to thank this entire community for existing and being so helpful and friendly. I discovered Pico-8 in April; at the peak of COVID-19 hitting my hometown, and in the depths of a massive depression brought on by isolation/lack of work/personal losses from the pandemic. It's been a lifelong dream to make a game, but I never thought I'd ever actually accomplish it, and making a little progress on this project each day feels like one of the few things that has really kept me going. So, thank you all!!!
Special thanks to @Liquidream for leading me here in the first place, and being kind enough to do some playtesting and providing lots of helpful feedback along the way. Also thanks to @MBoffin for their zine, which got me started, and for feedback in the forums when I was trying to figure out managing game state.
Also, I have a resprite with (better?) music up on itch.io:
https://ridgek.itch.io/killer-kegs
I think I'm here to stay! On to the next one!
Hi friends, does anyone have a hacky JS workaround for preventing pinch/zoom on itch.io in iOS? I just uploaded my first Pico-8 game there and it's more or less unplayable. (I don't own an Android device, so I don't know if this is also a problem on there.) Looks like the exported JS from 0.2.1b already employs a few workarounds to prevent touch gestures, but this doesn't do much when it's in an iFrame because you can still pinch and zoom on the parent document.
Hello, new friends! I discovered Pico-8 a few weeks ago and this is my first post in here!
I'm currently trying to create a framework to manage game state for some future creation, and am hoping to get some feedback on what I've put together so far. Any insight would be greatly appreciated; I'm a web developer and consider myself reasonably proficient in PHP/JS, but this is my first Pico-8 project/first video game/first time working with Lua/first time writing my own FSM ever, so I'm feeling very unsure of myself! I'm looking over it and asking myself questions like; have I over-complicated this? Does the game/level hierarchy make sense? Is it DRY enough? Is there a better way!? etc, etc!
The state hierarchy of the cart looks like this:
App |_Title Menu State |_Config Menu State |_Game State |_Init |_Running | |_Level State | |_Start | |_Running | |_End |_Over |
So, the first state the app is in is the Title Menu state, where you can either start the game or enter the Config Menu (for picking levels to start on or some other arbitrary config). From either of those, you can enter the Game State. Once we're in the Game State, it initializes, then begins running through the Level States (which just run 3s timers for demo purposes). Each level gets a Start state for saying 'ready, go' or whatever, a Running state for actually playing the game, and an End state for congratulating the player for completing the level or something.
One thing I did which I noticed is different from some of the tutorials I've seen is that I'm calling _init() rather than game_init() or level_init() when I make any state change. I realize this isn't super efficient, but I think it makes sense because any time I make a state change at any level, the program has to flow through the entire FSM hierarchy, which might be easier to debug in the future maybe? Does that make sense, or am I just wasting CPU cycles?
I'm looking forward to learning more from everyone, and hopefully making something actually enjoyable some day! Thanks!!! :)
Cart is attached, and also on GitHub