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 cartridge label (
__label__), the map (
__map__), sound effects (
__sfx__), and music patterns (
__music__). These sections are described in more detail below.
Except for the header and
__lua__ section, any section that is empty (is identical to the default cart) is omitted from the file. For each section, trailing lines that are identical to the default cart are also omitted. For example, if a cart's spritesheet only has sprites in the first row, lines representing subsequent rows are omitted from the
.p8 file. The default (empty) cart is just a header and an empty
__label__ sections exist -- impossible during regular work, but can be done with manual file editing, they will all be loaded: the graphics from the first section will be loaded first, and underneath that the data from the second section will also be loaded.
Every .p8 file begins with a two-line header:
pico-8 cartridge // http://www.pico-8.com version 8
version number has changed over multiple versions of PICO-8. However, the actual format of the file has not changed with every version increment.
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 Unicode characters, encoded in UTF-8, with similar appearances. For example, shift-C in the built-in editor (cat glyph) is stored as the cat emoji (🐱).
The spritesheet section begins with the delimiter
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 nybble first) in memory. This allows you to identify and draw images using hex digits with a text editor, if you like. If a manually edited file's
__gfx__ section includes characters outside of the hexadecimal range, they're loaded as pixels of color 0.
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. Note that this is encoded as a linear series of 4-bit pixels, rather than a series of 8-bit bytes. Tools reading this section and converting to byte format should treat the first hex digit of each pair as the bottom 4 bits and the second digit as the top 4 bits.
The sprite flags section begins with the delimiter
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 nybble 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.
If you have stored a screenshot for the cartridge label by pressing F7, the cart is saved with the screenshot. This is used as a cartridge "label" image when you save the cart as a
.p8.png file. The label is remembered in this way if you load a
.p8.png file and save it as a
The format for the
__label__ data is identical to that of the spritesheet, representing a square of 128 x 128 32-color pixels. Pixels in the default palette are encoded as hexadecimal digits from
f, and those in the alternate palette use
v. If a manually edited file's
__label__ section includes characters outside of the range from
v, they're loaded as pixels of color 0.
The map section begins with the delimiter
Map data is stored in the .p8 file as 32 lines of 256 hexadecimal digits (128 bytes). Each pair of digits (most significant nybble 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.)
The sound effects section begins with the delimiter
Sound data is stored in the .p8 file as 64 lines of 168 hexadecimal digits (84 bytes, most significant nybble 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 nybbles = 5 hex digits. (Two notes use five bytes.) The nybbles are:
- nybble 0-1: pitch (0-63): c-0 to d#-5, chromatic scale
- nybble 2: waveform (0-F): 0 sine, 1 triangle, 2 sawtooth, 3 long square, 4 short square, 5 ringing, 6 noise, 7 ringing sine; 8-F are the custom waveforms corresponding to sound effects 0 through 7 (PICO-8 0.1.11 "version 11" and later)
- nybble 3: volume (0-7)
- nybble 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.
The sound effects section begins with the delimiter
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.