Log In  

@zep Thanks for the clarification on PCM! For streaming via wavetable nodes - will there be some form of synchronization available to make sure timing lines up?

P#124568 2023-01-19 20:29

@zep That's great, thanks!

By the way, I saw what you said about split. Here's an implementation that has a convert parameter akin to PICO-8:

function split(str, sep, convert) -- Based on https://stackoverflow.com/a/7615129
    local t = {}

    str = tostring(str)
    sep = sep or ","
    convert = (convert == nil and true) or convert

    for v in gmatch(str, "([^" .. sep .. "]+)") do
        insert(t, (convert and tonumber(v)) or v)

    return t

I'm working on a complete re-implementation of the PICO-8 API within Picotron. If there are any PICO-8 functions you'd like help bringing over, let me know!

P#124580 2023-01-19 23:19

Hi @zep.

Glad to help. Another problem though. The screen seems a bit small now.

This is the frame I get running on Google Chrome, with no option to make the work screen bigger.

Is anyone else getting this small size ?

P#124583 2023-01-20 02:20 ( Edited 2023-01-20 02:51)

Bug report: crash when copy/pasting a huge block of text/code (> 1mb).

p64_playground_7.js:1 exception thrown: RuntimeError: memory access out of bounds,RuntimeError: memory access out of bounds
    at wasm://wasm/0020d80a:wasm-function[640]:0x6b6e9
    at wasm://wasm/0020d80a:wasm-function[496]:0x5badc
    at wasm://wasm/0020d80a:wasm-function[857]:0x7e841
    at Module.dynCall_v (https://www.lexaloffle.com/play/p64_playground_7.js:1:1225527)
    at browserIterationFunc (https://www.lexaloffle.com/play/p64_playground_7.js:1:1154454)
    at Object.runIter (https://www.lexaloffle.com/play/p64_playground_7.js:1:1157507)
    at Browser_mainLoop_runner (https://www.lexaloffle.com/play/p64_playground_7.js:1:1155976)
P#124604 2023-01-20 22:13

Hey @zep. I found a temporary solution for the small frame in Google Chrome.

Press CTRL and the "=" key (next to the backspace) until you get a perfect double-triple pixel size that fits your screen.

If you guys are experimenting, press CTRL and 0 (zero) to reset your viewing size.

P#124605 2023-01-20 22:57 ( Edited 2023-01-20 22:58)

I recently started having an issue with the code editor, about 3 days ago.

I am unable to paste in code that is more than roughly 20 lines or so.
When I open the playground and try pasting in my code, it instead pastes in zxc.
If i delete that, then it changes to pasting in nothing.
Whenever I press Ctrl+V I see the mouse cursor flicker and lag from about a frame, which indicates that something is definitely happening, but nothing actually gets pasted in.

I checked the Firefox dev console to see if it shows me anything, and this is what I see.
After that, pasting in anything (both small or big) adds 2 new lines to the console.
They are @@ navigator.clipboard.readText not found -- reading from codo_textarea and @@ get_clipboard_text called.
The only difference between pasting in small and big is that the second line appears once when successful, but 10 times when not.

Other than that, I've also noticed that Ctrl + Key combinations are pretty wack sometimes.
Ctrl+R sometimes also does Ctrl+V before running the application, which modifies code and crashes it.
Ctrl+V sometimes pastes my clipboard 4 times instead of only once, and a few times it didn't paste in anything at all (even when my clipboard was small).
Ctrl+A also runs Ctrl+V and/or Ctrl+R from time to time.

I checked both Firefox and Chrome, and everything is the same between them.
If you want to debug stuff with me to possibly find the issues, then you can contact me on Discord or by email.
My tag is SoundsDotZip#1143 and my email address is [email protected].

P#124630 2023-01-21 14:23

@zep said:
> There is still a difference with PICO-8 though: once a colour has been made transparent with palt(col, true), any remapping for that colour is lost and so palt(col, false) will revert to mapping to itself (i.e. palt(col, false) is the same as pal(col, col)).

I was kind of worried this sort of issue would arise from merging color writing and transparency into the blend tables.

I wonder if it would be better to have both the blend table and a single 64-bit hardware register somewhere that basically acted as a palette colorkey. This would be synonymous with the old PICO-8 palt() booleans. You could still technically accomplish 100% transparency / 100% opacity with the blend tables, but palt() would toggle bits in this register instead of rewriting a row in the table.

It'd make handling transparency changes more efficient host-side, though it'd necessitate one extra test/branch per pixel of course, but the savings of not having to run the src/dst through the 2D lookup table and then having to re-write the pixel as the same color it already is might offset that. It's basically an early-out, a stencil based on color, just like modern GPUs early out if the depth stencil (aka z-buffer) test fails and they don't bother doing the fragment shading for the pixel.

P#124733 2023-01-23 20:12 ( Edited 2023-01-23 20:21)

@Felice The thing I'm more irritated by is when you try to draw a black shape and it does nothing. The palt issue is a minor one and I can see how it can trip you up if you're used to it remembering the previous pal setting, but I don't see the need for it myself. (Usually, when I want to draw black on a sprite, I use pal(i,0) rather than making a different color transparent and black opaque, as I think it's more token efficient.) But whereas in PICO-8 it would ignore palt for shape statements, rather often in Picotron, I draw a black circle and then wonder for half an hour trying to figure out why the ₣¥€₭ doesn't it work??? before I figure out that I might as well have been dipping my digital paintbrush with nothing before wiping it on the virtual canvas. Of course, now that I'm used to it I now know to use color #32 instead, but it still tripped me up far more than palt destroying the previous color ever could. (Though, I'll admit that I am an amateur programmer so take my opinion with a grain of salt.)

P#124790 2023-01-24 21:25


I have done it! I have made a recreation of Minesweeper in Picotron, meaning this is technically the first game for Picotron.

{-EDIT: As has been pointed out below, this may not be the first game made for Picotron. It is, however, as far as I (and others) can tell the first game released for Picotron. While I was editing this post, I also added some comments next to the adjustables to recreate the difficulty settings for the original game.-}

{-ANOTHER EDIT: I have now updated the game to version 3, so this post will remain for the old version only. If you want to play or talk about version 3, go to this thread.-}

To load it in Picotron:

  • Paste the following code into the code editor:

    -- Minesweeper (v2)
    -- By: Kai
    -- GFX decoder
    function decode(str)
    return userdata(chr(91,103,102,120,93)..str..chr(91,47,103,122,120,93))
    -- GFX: faces
    -- GFX: tiles
    -- GFX: numbers
    numbercols={12,27,24,16,2,17,13,32} numbers={
    -- adjustables
    -- beginner: 9x9/10
    -- intermediate: 16x16/40
    -- expert: 30x16/99
    width=10 -- min: 7 | max: 59-60
    height=10 -- min: 1 | max: 31-32
    mines=10 -- idealy ~10-20% of total tiles
    -- other setup
    -- data format:
    -- bit 0: mine
    -- bit 1: uncovered
    -- bit 2: flagged
    -- bit 3: unused (?)
    -- bit 4: unused (?)
    -- bit 5: unused (?)
    -- bit 6: unused (?)
    -- bit 7: unused (?)
    -- debug: randomized test board
    --for x=0,width-1 do
        --for y=0,height-1 do
    -- /debug
    function place_mines(cx,cy)
    local candidates={}
    for x=0,width-1 do
        for y=0,height-1 do
            if (abs(x-cx)>1 or abs(y-cy)>1) add(candidates,{x,y})
    for i=1,mines do
        local position=candidates[flr(rnd(#candidates))+1]
    function bit(n,b,c)
    if type(c)=="boolean" then
        return c and n|2^b or n&255-2^b
        return n&2^b>0
    function uncover(tx,ty)
    if (bit(get(minefield,tx,ty),1)) return
    local nearbymine
    for xdelta=-1,1 do
        for ydelta=-1,1 do
            if (bit(get(minefield,tx+xdelta,ty+ydelta),0)) nearbymine=true
    if not nearbymine then
        for xdelta=-1,1 do
            for ydelta=-1,1 do
                local x=tx+xdelta
                local y=ty+ydelta
                if (x==mid(0,x,width-1) and y==mid(0,y,height-1) and not bit(get(minefield,x,y),1) and not bit(get(minefield,x,y),2)) uncover(x,y)
    elseif bit(get(minefield,tx,ty),0) then
    function _draw()
    mbp=mb&~lmb -- mb pressed
    lmb=mb -- last mb
    if (not (dead or won or start)) timer=min(timer+1/60,999)
    local tx=(mx-1)\8
    local ty=(my-20)\8
    if tx==mid(0,tx,width-1) and ty==mid(0,ty,height-1) and not dead and not won then
        -- on grid
        if bit(mbp,0) and not bit(get(minefield,tx,ty),1) and not bit(get(minefield,tx,ty),2) then
            if (start) place_mines(tx,ty) start=false
            if not dead then
                local coveredtiles=0
                for x=0,width-1 do
                    for y=0,height-1 do
                        if (not bit(get(minefield,x,y),1)) coveredtiles+=1
                if (coveredtiles==mines) won=true
        elseif bit(mbp,2) and not bit(get(minefield,tx,ty),1) and not start then
            remainingmines+=bit(get(minefield,tx,ty),2) and -1 or 1
    elseif mx==mid(width*8/2-8,mx,width*8/2+7) and my==mid(2,my,17) and bit(mbp,0) then -- clicked on face
        -- reset puzzle
        for x=0,width-1 do
            for y=0,height-1 do
    -- draw game
    local emote=dead and frown or won and cool or bit(mb,0) and curious or smile
    for x=0,width-1 do
        for y=-0,height-1 do
            local tile
            local tdata=get(minefield,x,y)
            local showneighbors
            if bit(tdata,1) then -- uncovered
                if bit(tdata,0) then -- mine
                else -- no mine
            else -- covered
                if bit(tdata,2) or won then -- flag
                    if bit(tdata,0) or not dead then -- correct or still playing
                    else -- game over correction
                else -- no flag
                    if bit(tdata,0) and dead then -- game over clairvoyence
                    else -- nothing special
            if showneighbors then
                local closemines=0
                for xdelta=-1,1 do
                    for ydelta=-1,1 do
                        if (bit(get(minefield,x+xdelta,y+ydelta),0)) closemines+=1
    local str=mid(-99,flr(remainingmines),999)
    if str<-9 then
        -- do nothing
    elseif str<0 then
    elseif str<10 then
    elseif str<100 then
        -- do nothing
    local str=mid(-99,flr(timer),999)
    if str<-9 then
        -- do nothing
    elseif str<0 then
    elseif str<10 then
    elseif str<100 then
        -- do nothing
    -- debug: display mouse statistics
        --print("mx: "..mx,width*8+2,1,27)
        --print("my: "..my)
        --print("mb: "..mb)
        --print("mbp: "..mbp)
        --print("tx: "..tx)
        --print("ty: "..ty)
    -- /debug

  • Optionally, edit the adjustable variables width, height and mines to change the difficulty.
  • Either hit Ctrl+R or, for the optimal experience, continue reading.
  • Type save minesweeper and hit enter.
  • Type terminal and hit enter to go to the desktop.
  • In the desktop terminal, type or paste in run_program_inside_terminal"minesweeper.p64/main.lua" and hit enter.
  • Adjust the size of the window to make it fit perfectly.
  • Play! Use the left mouse button to uncover a tile, and the right mouse button to place a flag where you think a mine is. Click the smiley face to restart. Numbers indicate how many mines are in the eight surrounding tiles. The number in the top left is an estimation of how many mines you have left to find, based on the total number of mines and how many flags you have placed down, and the number in the top-right shows your current time in seconds. Uncovering a mine leads to a game over, while uncovering all non-mine tiles causes you to win. Enjoy!
P#124805 2023-01-25 05:05 ( Edited 2023-04-07 21:42)

Very cool work @Kaius 👍
(with great, clear instructions!)

As for first Picotron game - quite possibly.
I saw a couple others making games on the Pico8 Discord, but don't think they've posted the code yet.

Also, I did see this posted on Twitter on Jan 16th
But again, they don't appear to have posted any source - so unable to verify if they're just abusing the hashtag:

Moar Picotron games FTW! 😉

P#124812 2023-01-25 06:41

Okay so the "bug" I reported before (it's above this by a few posts) was actually on my end.
One of my antivirus' settings made me unable to paste anything too big.
I tweaked the options and now it works fine.

P#124853 2023-01-25 19:51

Certainly not the first program posted for Picotron in Lexaloffle, @Kaius. :) I made my demo and set it so others can use the graphics in it.


Still ... it's not good there are so many shortcomings in Picotron. I may wait a-while for some bugs to be fixed before I build anything more in it.

P#124872 2023-01-26 04:42

congrats on the first game Kaius!

(not the first doodle, experiment or cart, but the first published game)

[- edit to avoid going more off-thread here: wth is that reply? people on the forum can point out incorrect or obnoxious messages. I will post carts when I want to. -]

P#124904 2023-01-26 22:43 ( Edited 2023-01-28 01:44)

Indeed @merwok. You've certainly been with us for over 3-years now. I look forward to you writing and posting in lexaloffle your very first Pico-8 program.

Congrats go to you too, @Kaius for writing the first fully-functional game in Picotron. Well done !

I'm not going to code in Picotron again though until some of the bugs are worked out - yet I am always glad to code and share my code in Pico-8. :)

Grand cheers for @zep who is always looking to the future !

P#124912 2023-01-27 04:28 ( Edited 2023-01-27 04:33)

Bug report: set_draw_target breaks _draw


function _init()

function _draw()
    for i=0,240-1 do
     for j=0,135-1 do

    -- bug: cls & print are not displayed

moving set_draw_target (+ render to memory) to _update restores correct behavior.

P#125139 2023-02-01 21:12 ( Edited 2023-02-01 21:12)

Can you post your fixed code? I put all my code in update but it's still not displaying anything after I change the draw target:

function _init()
    scr1 = userdata("u8", 480, 270)
function _update()

    -- bug: cls is not displayed
P#125203 2023-02-02 21:56

@freds72 @rilden From testing, it seems that set_draw_target() does NOT reset the draw target as it is (seemingly) supposed to. It is only reset between _update and _draw calls, so once you use set_draw_target, there is no going back until the end of the _update/_draw function. This program shows this bug by printing the working function(s).

function _init()
    cls() -- erase anything from all the previous testing. (just in case)
function _draw()
    set_draw_target() -- note that we don't reset this, nor do we set it TO anything at all in the first place!
    print("_draw",10,20,11) -- this fails...
function _update()
    print("_update",10,10,8) -- ...but this works!
P#125223 2023-02-03 06:21

Yep, what I've been doing is storing the draw target via draw_target = get_draw_target() and using set_draw_target(draw_target)

P#125316 2023-02-04 18:05

@HTV04 Thanks! I didn't know that get_draw_target() existed. Here's a program I made while testing this function, utilizing the ability to make procedural sprites:

function _draw()
function proc_gen_spr(col,shade,shine,size)
    local last_dt=get_draw_target()
    local procedural_sprite=userdata("u8",size,size)
    return procedural_sprite

Also, here's a better version of set_draw_target that resets the draw target when no argument is supplied:

-- on startup
dscr=get_draw_target() -- the original display screen.
-- new function
function set_dt(dt) -- shorter name for the original function.
    set_draw_target(dt or dscr) -- literally all that's needed.
end -- ...and that's it.
-- testing
--set_dt(userdata("u8",128,128)) -- a simulated PICO-8 screen perhaps?
cls(7) -- you WOULD notice this, but you don't, 'cause it ain't there!
set_dt() -- resetting the draw target.
circfill(240,135,100,8) -- you DO notice this, however.

(Note to self: I need to be looking into pancelor's function-lister some more.)

P#125350 2023-02-05 09:31

thanks for the investigations but I still see that as a bug :)

P#125377 2023-02-05 21:18 ( Edited 2023-02-05 21:18)

@freds72 Oh, it's definitely a bug. I mean, even zep thought that set_draw_target() worked the way it should. Need proof?

function _init()
    b = userdata("u8",8,8)

    sx = 20 sy = 20

That code snippet above comes from the fillp demo, specifically the _init function which draws the initial fill pattern consisting of a small, hollow circle. To do this, the draw target is set to the fill pattern, and then set back... but, we obviously know that's not what happens. Instead, set_draw_target() seems to do nothing, as evidenced by what happens if you add in a cls(28) line or other drawing function after the draw target is supposedly reset, but before the end of the _init function.

P#125399 2023-02-06 07:12

could i run a program as a desktop wallpaper in picotron?

P#126631 2023-03-05 18:00

this is so very very cool.

i'm really excited by this. i'm playing around with it a bunch as it is, regardless of the current limitations, and can't wait for a desktop release.

i absolutely love how much of the system is exposed and hackable via the system/ subdirectory. it was really fun to edit system/terminal.lua, hit ctrl+s, ctrl+r the terminal, and see my changes take effect. immediately excited to mod the system to fill in some gaps, even though my work is likely to be redundant in future releases.

i really like playing around with building little games and programs in pico-8, it's a really great experience, but this workstation concept is so up my alley it's crazy. i really love building tooling and hacking on little system things. i sate my need to do so with my linux systems now but this is just so much cozier and friendlier with your little-systems charm, zep.

would drop money on this to fund development in a heartbeat, even in its current state, btw. but hopefully not too much development, got to leave some for the rest of us old systems hackers


P#126744 2023-03-07 22:32

I had to make an account just to say woah. This thing has so much potential! I love that the system source code is accessible from within the system, really cool concept can't wait to see more from this project in the future :D

P#127382 2023-03-21 01:00

Picotron Minesweeper v.3

I have now posted a new version of Picotron Minesweeper! The new version is in this thread if you want to see it or discuss it.

P#128270 2023-04-07 21:39

This is super cool! Will/could Picotron have access to the internet allowing for multiplayer?

P#128453 2023-04-11 22:24

@Johste Sooo... um... wow. I was literally juuuuuust thinking about a game concept I had that would have REQUIRED internet access to play as part of its central gimmick. For those who are curious, here's a brief explanation:

Four adventurers are placed at the entrance to a dungeon (think back to classic roguelikes), at the end of which is an evil dragon. (Really, is there any other kind?) This would be easy if all the players were on the same page, but they simply aren't. Only one of them truly cares about killing the dragon, another one just wants to get treasure, another one is a traitor who wants to kill everybody else, and yet another one is here to kill the traitor, and you only know what you want. All players gain points for playing to their 'agenda'. So imagine you are the 'hero' and want to kill the dragon, and you walk into a room with two other people trying to kill each other. Who is who? Is one of them the 'detective' trying to bring the traitor to justice? Is the traitor trying to snuff out the one who they think is the detective? Or is one of them the greedy guy who is trying to kill somebody for their wallet, regardless of who they are? You're gonna have to think about their past actions if you want a hint towards the answer. And while you're thinking about that, how are THEY going to think about you? And so on.

If you didn't read that, don't worry, it's not that important, and I'm still mulling over the details of it in my head so some of what was said there is subject to change. What IS important is that this concept simply would NOT work on a single screen. The game revolves around you not knowing what the other players are up to, and that breaks down if you all share a single screen.

But then, as I'm doodling a few sprites related to it in PICO-8 out of boredom, I look back to the Picotron thread (also out of boredom) and see somebody else asking for network capability! I thought I might have been the only one who might have wanted something like this, but I'm glad I'm not.

Even if full online capability isn't implemented, I would still like at the very least LAN capability to allow for things like what I just described without having to resort to really weird hacks that are undocumented for a reason.

P#128480 2023-04-12 20:07

@Sosasees I also like the thought of having a program as a desktop background, although I couldn't get it to work quite like I wanted it to... editing /system/wm.lua directly just doesn't work because the window manager appears to already be loaded and running, even before the desktop view is actually open. The only way I've found to actually have an effect is to run the code in the terminal, but I haven't found a way to get a window in a desktop running from a terminal, so this approach isn't ideal either. The best way to do this would be to edit /system/wm.lua directly and then restart Picotron, but this isn't possible in Playground at the moment due to the lack of permanent data storage. Still if you want to see the program I cooked up for use as a desktop background, then just follow these steps:

  • Type edit /system/wm.lua into the command prompt and press enter.
  • Hit Ctrl+A, then Ctrl+C.
  • Open the code editor and hit Ctrl+V.
  • Comment out lines #530 and #535. (For bonus points, change the color value on the print statements just below them to be 24 instead of 7.)
  • Also comment out lines #514-#521 and paste the following magic code right before or after it:
    ripples=ripples or {}
    lmb=mb or 0
        if r.t<=0 then
        elseif r.t<=5 then
        elseif r.t<=10 then
        elseif r.t<=15 then
    local chance=stat(1)
    while rnd()<chance do
    if (mbp>0) add(ripples,{x=mx,y=my,r=0,c=7,t=20})

    After that, hit Ctrl+R.

I call this background 'Ripples', due to... well, what it looks like. Anyways, this program both has interactivity in the form of making a ripple whenever you click, while also doing its own thing by occasionally creating ripples randomly. It even has a bit of utility, as how many random ripples are created depends on the CPU load; by default it will make very few ripples, but if you insert while stat(1)<.5 do end just before local chance=stat(1), significantly more ripples appear. I would love to test out how it looks on my Minesweeper program, but, as stated above, that doesn't seem to be possible in Playground yet. :(

P#128488 2023-04-13 01:34

Hey speaking of audio, can you elaborate on what you mean by "64-node synth"? Just from the sound of it, it almost sounds like some sort of modular design??

P#129182 2023-04-30 13:41

@IMLXH I guess that's like custom instruments in PICO-8. In other words, PICO-8 custom instrument is a kind of 32-node synth.

P#129466 2023-05-07 08:59 ( Edited 2023-10-09 14:41)

Possible bug with large numbers?...

poke8(0x5500,~0xFFFFFFFFFFFFFFFF) --works
poke8(0x5500,~18446744073709551615) --errors

Trying to invert a large decimal produces an error. (The same value works as a hexadecimal).

> <pre>
:38: number has no integer representation

P#132864 2023-08-08 11:19


Try reposting this in part 2 on Zep's blog. You might have a better chance of getting a response there.

P#135731 2023-10-10 23:10 ( Edited 2023-10-12 16:21)
P#135737 2023-10-11 05:27

Got random crashes when using (a lot?) userdata (code runs fine and then crash):

p64_playground_11.js:1 Uncaught RuntimeError: memory access out of bounds
    at 00276a26:0x1943b
    at 00276a26:0x1a7ec
    at 00276a26:0x27e1d
    at 00276a26:0x16ce9
    at 00276a26:0x98a8f
    at Module.dynCall_vii (p64_playground_11.js:1:1761334)
    at invoke_vii (p64_playground_11.js:1:1755776)
    at 00276a26:0x15735
    at 00276a26:0x16930
    at 00276a26:0x75bac
P#138449 2023-12-08 17:24 ( Edited 2023-12-08 17:25)

How much will it cost when released?

P#141562 2024-02-16 17:14

see https://www.lexaloffle.com/picotron.php?page=faq

note that this thread is inactive, you can use the second one

P#141605 2024-02-17 20:46

> ### How Much will Picotron Cost?
> $20 (One time fee, DRM-free, cross platform, future updates included). When purchased with PICO-8 or Voxatron, it is only $12 (existing customers will be able to upgrade to this deal when 0.1 is released).

— Picotron FAQ

P#141610 2024-02-17 23:11

[Please log in to post a comment]