Log In  

I just tried exporting a cart I made and I noticed that the .js file is fairly large compared to the actual cart size (1.1MB vs 3KB in PNG format). I realize that some of this is the player itself, but also noticed that the cart data is stored rather inefficiently (a javascript array with the elements represented as text integer values).

Couple of questions here -- first, has anyone separated the player code from the cart code so that they are in separate files and can be cached separately? Seems rather inefficient to have to reload the player each time a cart is changed, especially on mobile devices where someone may be downloading over a limited data plan or even on the server side where someone pays for amount of data they serve (like on Amazon's S3).

As for the cart data, is there any plans to modify the web player to load a more compact format? Ideally, it would be able to load the .p8.png file directly, but even doing some compression inside the javascript would help out a lot, IMO.

Thanks!

P#19036 2016-03-01 09:06 ( Edited 2016-03-26 18:55)

There is a PicoLoader project on Github here. Basically, it loads the pico8.js file from here (or you can host it on your own server), and lets you load a .p8.png file into a specified container using PicoLoad('container', 'cart.p8.png'). The only problem is that pico8.js, for some reason, is actually larger than the one generated from exporting which also already has your game in it. Why this is, I have no clue and haven't looked into it yet.

I'll take a look tonight and see if I can figure out why the one on lexaloffle is larger than the one that actually has the game in it. I suspect it could have something to do with the extra code for decompressing the png, but we'll have to see.

P#19058 2016-03-02 16:30 ( Edited 2016-03-02 21:30)

Upon further inspection, it's almost impossible to tell what's going on because of it being minified. Even beautifying it doesn't help much because all of the names for everything are obviously changed to things like single letters. The png probably stores the Lua code (in binary of course), so I'm thinking there might be a JS-based Lua interpreter in there, and that's probably why that JS file is larger. It's really hard to say though, and the only one who probably knows is Zep.

It looks like there are several libraries included in the script (emscripten, ASM.js, etc), some or all of which could possibly be stripped down to the bare necessities, if Zep hasn't already done so. There might be other ways to knock down the file size as well, such as running it through Closure Compiler and/or removing the code that does debugging/error output. Sorry I couldn't be more help - I totally understand the desire to cut the filesize down as far as possible for bandwidth reasons, or because of a lot of game jams having various filesize limits. Having the JS exports, or the Pico-8 player script, all being over 1MB can put a dent in some things.

Maybe in a future release, Zep will consider allowing us to add a flag to the export function to export a production version of the script without any of the debugging/error logging stuff in it. Maybe make a feature request here in the forums for something like that.

Hope you can figure something out though!

P#19094 2016-03-06 17:31 ( Edited 2016-03-06 22:45)

Pretty sure the vanilla HTML5 export is just an asm.js compiled version of the exact same executable source code Pico-8 runs normally. The reason it's so much bigger is partly because, yes the binary-as-a-text-array format is a lot less compact, but also PNG has compression as part of its format, whereas JavaScript does not.

P#19104 2016-03-07 14:58 ( Edited 2016-03-07 19:59)

The Pico-8 executable isn't in the png. For the BBS to play png carts, it loads a modified version of the Pico-8 executable (just the player itself) as a binary .dat file into a javascript that uses asm.js and emscripten to decode and run it. Think of the carts just like any other cart for Atari or NES - it just contains the game data, not the console itself.

The "compression" in the png format is pretty much just converting the ASCII in the p8 file to binary, but there may be actual compression methods at work as well (like he probably uses something like LZ to compress the ASCII first, then converts that output to png).

In the case of HTML5 export however, it outputs the player as well as the cart as arrays of integers (obviously it wouldn't be very efficient to put the ASCII representation of binary data into a text file, since you can't put actual binary into a text file, so this is a custom encoding). When you export a project as HTML5, it just has the Pico-8 player as well as your (encoded) game code embedded in a single script (along with asm.js and emscripten, just like the BBS script), so it doesn't need all 3 files separately.

Since javascript is only plain 'ol text files and you can't put binary into them, outside of the ASCII representation of said binary as strings of "10101010", it would be 64 times larger than the actual binary, since each bit is represented in ASCII as a byte. You could probably use something like Huffman compression on it though to make it much, much smaller (trying to replace each binary byte with as close as possible to 1 ASCII byte (plus delimiter)), which is what's going on in the HTML5 exporter (it's not Huffman compression, but it's something similar in the form of replacing each byte with some kind of ASCII character replacement system and key to decode it).

In any case, since it's javascript, whether you load an actual binary into it or some encoded representation thereof, you still have to account for the size of the script needed to decode it, which is going to vary in complexity depending on the encoding that it's decoding, if that makes sense.

TL;DR - the BBS player plays the png carts and uses a different script from the HTML5 exporter, but both accomplish (basically) the same tasks, except that the HTML5 exported script doesn't play png carts. Additionally, the HTML5 exporter outputs a smaller file than the 3 combined files used to play carts on the BBS, probably because of the extra code that's needed to decode the player and cart as binaries, rather than whatever script is used to decode them as javascript arrays.

I haven't really taken a serious look at how exactly the scripts work or how the various formats are exported from Pico-8, most of this is just semi-educated guessing, so take it with the appropriate amounts of sodium.

P#19239 2016-03-15 10:14 ( Edited 2016-03-15 14:45)

Background on the .p8.png storage format: https://www.lexaloffle.com/bbs/?tid=2400

A Python implementation of both a .p8 cart reader and a .p8.png cart reader: https://github.com/dansanderson/picotool/blob/master/pico8/game/game.py

(See comments in other picotool files for explanations of the differences between the .p8 (ASCII) storage format and the binary layout.)

I haven't looked at the web player at all, but from your description it sounds like it's using a version of the binary layout serialized as a JS number array. I don't see a reason why it would use the PNG format on top of that, but it might as well use the internal compression method for the code data. The data regions could also be compressed (especially if they're partially empty) but I'd have to look to check if they are. They aren't compressed in the PNG substrata, instead relying on the PNG format to compress the cart label + data like it normally would.

From there, it sounds like a base64 string would be more compact than a JS array (1.25x binary size vs. ~3x). That doesn't seem like a big enough difference to worry about when distributing a single game with the standalone player as JS. But it'd add up pretty fast in a hypothetical case of distributing multiple carts in a single bundle.

P#19415 2016-03-26 14:21 ( Edited 2016-03-26 18:21)

Well, I guess the main advantage of playing the .png carts on your own web server would be, if you had multiple games, there would only be a single download of the .js player, after which it would be cached (and if you use a CDN like Cloudflare, the .js file would be served from there instead of your server as well).

This way, the user would have the player script in cache and only have to download the ~32k carts for each game, instead of having multiple ~1MB .js files (one for each game). I can see how 1MB per game could potentially add up, especially since most good hosting services (AWS, Heroku, DigitalOcean, dedicated solutions, etc.) have metered bandwidth. As a web developer for almost 16 years, anything that claims "unlimited bandwidth" is horrible in my experience (and is usually also a lie), so bandwidth is a real concern if you have a semi-popular site.

P#19416 2016-03-26 14:55 ( Edited 2016-03-26 18:55)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-29 11:51:58 | 0.007s | Q:16