Pico-8 can save cartridges in two file formats: the .p8 format, and the .p8.png format. The save command will use the format that corresponds to the filename extension.

The .p8 format is a text-based format that is suitable for using in external text editors and source control repositories (like GitHub). In particular, the Lua code for the cart is stored as plaintext near the top of the file, which makes it easy to use an external text editor as a replacement for Pico-8's built-in code editor without using a third-party tool.

Non-code sections (such as graphics) are stored as strings of hexadecimal characters representing bytes. The exact format differs for each section.

The sections appear in the following order: a header, the Lua code (__lua__), the spritesheet (__gfx__), the sprite flags (__gff__), the map (__map__), sound effects (__sfx__), and music patterns (__music__). These sections are described in more detail below.

Header Edit

Every .p8 file begins with a two-line header:

pico-8 cartridge //
version 8

The version number has changed over multiple versions of Pico-8. However, the actual format of the file has not changed with every version increment.

Lua Edit

The Lua section begins with the delimiter __lua__ on a line by itself. Subsequent lines up to the next delimiter (__gfx__) contain the cart's Lua code as plaintext.

It is possible to use an external text editor to insert characters in the Lua code section that the built-in editor does not support. Uppercase ASCII letters appear as lowercase in the built-in editor, and are converted to lowercase if the cart is saved by Pico-8. Non-ASCII characters may not appear correctly in the built-in editor.

The built-in editor stores all letter characters as lowercase. Glyphs are stored as higher byte values. For example, shift-C in the built-in editor (cat glyph) is stored as the byte value 0x82 (not an ASCII uppercase A).

Spritesheet Edit

The spritesheet section begins with the delimiter __gfx__.

The spritesheet is represented in the .p8 file as 128 lines of 128 hexadecimal digits. Each line is a pixel row, and each hexadecimal digit is a pixel color value, in pixel order.

This differs from the in-memory representation in that the 4-bit hexadecimal digits appear in pixel order in the .p8 file, while pairs are swapped (least significant nibble first) in memory. This allows you to identify and draw images using hex digits with a text editor, if you like.

A cart is allowed to use the bottommost 128 sprites as the bottommost 128x32 tiles of the map data. That is, if the cart calls map() with coordinates in that region, the data is read from the bottom of the spritesheet, and the map editor can view this memory either way. In the .p8 file, this data is always saved in the __gfx__ section, even if the cart uses it as map data.

Sprite flags Edit

The sprite flags section begins with the delimiter __gff__.

Flags are represented in the .p8 file as 2 lines of 256 hexadecimal digits (128 bytes). Each pair of digits represents the 8 flags (most significant nibble first) for each of the 256 sprites, in sprite ID order.

In the graphics editor, the flags are arranged left to right from LSB to MSB: red=1, orange=2, yellow=4, green=8, blue=16, purple=32, pink=64, peach=128.

Map Edit

The map section begins with the delimiter __map__.

Map data is stored in the .p8 file as 32 lines of 256 hexadecimal digits (128 bytes). Each pair of digits (most significant nibble first) is the sprite ID for a tile on the map, ordered left to right, top to bottom, for the first 32 rows of the map.

The map area is 128 tiles wide by 64 tiles high. Map memory describes the top 32 rows. If the cart author draws tiles in the bottom 32 rows, this is stored in the bottom of the __gfx__ section. (See above.)

Sound effects Edit

The sound effects section begins with the delimiter __sfx__.

Sound data is stored in the .p8 file as 64 lines of 168 hexadecimal digits (84 bytes, most significant nibble first), one line per sound effect (0-63).

The byte values (hex digit pairs, MSB) are as follows:

  • byte 0: The editor mode: 0 for pitch mode, 1 for note entry mode.
  • byte 1: The note duration, in multiples of 1/128 second.
  • byte 2: Loop range start, as a note number (0-63).
  • byte 3: Loop range end, as a note number (0-63).
  • bytes 4-84: 32 notes

Each note is represented by 20 bits = 5 nibbles = 5 hex digits. (Two notes use five bytes.) The nibbles are:

  • nibble 0-1: pitch (0-63): c-0 to d#-5, chromatic scale
  • nibble 2: waveform (0-7): 0 sine, 1 triangle, 2 sawtooth, 3 long square, 4 short square, 5 ringing, 6 noise, 7 ringing sine
  • nibble 3: volume (0-7)
  • nibble 4: effect (0-7): 0 none, 1 slide, 2 vibrato, 3 drop, 4 fade_in, 5 fade_out, 6 arp fast, 7 arp slow; arpeggio commands loop over groups of four notes at speed 2 (fast) and 4 (slow)

Note that this is very different from the in-memory layout for sound data.

Music patterns Edit

The sound effects section begins with the delimiter __music__.

Music patterns are represented in the .p8 file as 64 lines, one for each pattern. Each line consists of a hex-encoded flags byte (two digits), a space, and four hex-encoded one-byte (MSB-first) sound effect IDs.

The flags byte has three flags on the lower bits (the higher five bits are unused):

  • 0: begin pattern loop
  • 1: end pattern loop
  • 2: stop at end of pattern

The sound effect ID is in the range 0-63. If a channel is silent for a song pattern, its number is 64 + the channel number (0x41, 0x42, 0x43, or 0x44).

Note that this is different from the in-memory layout for music data.

Ad blocker interference detected!

Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.