PICO-8 Wiki
Advertisement

The P8SCII character set includes 16 control codes that produce effects when printed to the screen. These are typically invoked using escape sequences in string literals, as shown below. They can also be printed by code number via chr().

Some control codes accept arguments as characters printed immediately after the control code. In some cases, an argument is a single character that represents a numeric value. This character is typically a digit 0-9 (values 0-9) or a letter a-z (values 10-35). For attributes that accept larger values (such as audio settings), values above 35 can be entered with any P8SCII character above the higher z: { is 36, | is 37, 🐱 is 43, and so on.

Control code parameters are noted below, as in the official documentation, as P0 and P1.

Positioning text[]

Several control codes adjust the cursor position when printed. Subsequent printing continues from the new cursor position.

These codes replicate the corresponding behavior of an ASCII terminal:

  • \b : Backspace. Moves the cursor one character width (4 pixels) to the left. This does not erase any characters from the screen.
  • \t : Tab. Advances the cursor to the next tab stop to the right. By default, tab stops are four characters (16 pixels) wide.
  • \n : Newline. Advances the cursor to the next line and returns it to the current left margin (either 0 or whatever was last set by cursor()). If the cursor is at the bottom of the screen, this scrolls the screen up, similar to a teletype.
  • \r : Carriage return. Returns the cursor to the current left margin without advancing to the next line.

When printed to a terminal using printh(), these codes behave as their ASCII counterparts. These are the only control codes that do this in a terminal.

print("initials\tscore")
print("aaa\t\t100000")
print("bbb\t\t090000")
print("ccc\t\t080000")

Tip: You can adjust PICO-8's tab stop width with a special command character code. See \^s below.

Three control codes can shift the cursor by a number of pixels:

  • \- P0 : horizontal offset
  • \| P0 : vertical offset
  • \+ P0 P1 : horizontal and vertical offsets

The value 16 is subtracted from these parameters, allowing for an actual range of offsets from -16 to +19.

-- offset each word by +4 pixels vertically ("j" = 20, 20 - 16 = +4)
print("my \|jawesome \|jgame")


Changing text colors[]

Two control codes change the text color:

  • \f P0 : foreground color
  • \# P0 : background color

Each code takes one parameter, a hexadecimal character corresponding to the PICO-8 color value.

print("\f6hello \f3goodbye")

print("\f7my \f5\#9awesome\f7\#0 game")

The background color is reset to transparent at the end of the print() function. The foreground color is not reset. Changing the foreground color with a control code is similar to changing the pen color with color() or any of the drawing commands (such as print()'s color argument).

Note: Color control codes do not follow the palette settings of the draw state for draw operations, as set by pal() pal(..., 0) and palt(). They do honor full-screen palette swaps via pal(..., 1).


Special commands[]

The special command control code can perform visual effects based on arguments. The first code is \^, followed by a command character and any arguments expected by that command.

Skipping frames (pausing)[]

\^1 through \^9 skips a number of frames before continuing printing. The number of frames to skip corresponds to the number: 1, 2, 4, 8, 16, 32, 64, 128, or 256 frames, respectively.

print("3...\^6 2...\^6 1...\^6 blastoff!")

All program execution stops while print() waits for the frames. _update() and _draw() are not called for these frames.

function _update() end
function _draw()
  cls()
  print("🐱", rnd(120), rnd(120), rnd(16))
  print("3...\^6 2...\^6 1...\^6", 0, 0, 7)
end

Delaying between characters[]

\^d P0 causes subsequent printing to pause P0 frames between each character, to the end of the string (or the next \^d directive). Unlike skipping frames, P0 is the number of frames, not a power of 2.

All program execution stops while print() waits for the frames. _update() and _draw() are not called for these frames.

print("\^d3it's dangerous to go alone. take this!")

Clearing the screen[]

\^c P0 clears the screen with a given background color. It also resets the cursor position to (0, 0).

print("\^c3\f7it's a new day!")

Homing the cursor[]

When you call print(), the starting position of the cursor is considered the "home" position. \^g returns the cursor to its home position.

print("\n\ndown here\^gno up here!")

\^h updates the home position to be the cursor's current position.

print("\n\ndown here\n\^h\n\n\nfurther down\^gand i end up here!")

Moving the cursor to an absolute position[]

\^j P0 P1 sets the cursor to an absolute (x, y) pixel position. Each parameter value is multiplied by 4.

-- coordinates x=40 ("a" = 10, 10 * 4 = 40), y=48 ("c" = 12, 12 * 4 = 48)
print("\^jacgame over")

Setting the tab stop width[]

By default, the tab stop width is 16 pixels, equivalent to four 4-wide characters. You can change the tab stop width using the \^s P0 special command. The argument is the tab stop width in pixels.

print("\^samonth\tdeposit\tbalance")
print("\^sa1\t500\t500")
print("\^sa2\t250\t750")
print("\^sa3\t325\t1075")

Note: As with most control code effects, the tab stop width resets to 16 pixels at the end of the print() call.

Setting the righthand side print border[]

When you call print() without pixel coordinates, PICO-8 maintains a cursor position, and if the cursor reaches the righthand side of the screen, its location wraps to the beginning of the next line.

The \^r P0 code sets the righthand border location to an x coordinate equal to P0 multiplied by 4.

-- uses \^j to set the cursor to x=40 y=48, and
-- sets the wrap border to x=56 ("e" = 14, 14 * 4 = 56)
print("\^jac\^regame over")

Setting the character size (cursor advance rate)[]

\^x P0 and \^y P0 set the effective width and height of each character for the purposes of advancing the cursor. The parameter is the number of pixels.

By default, the width and height are that of a standard character: 4 x 6. When using a custom font, the custom font width and height are used instead (see section: Custom fonts). Increasing the sizes from those values causes letters to print farther apart. Decreasing the sizes causes them to print closer together or overlapping.

When a wide character (128 and above) is printed, the width is equal to the value passed to \^x + the difference between the standard character width and the wide character width for the current font. With the standard font, the difference is 4, so wide characters will effectively appear 4px wider than standard characters. For custom font, however, this depends on the two character widths that have been setup. For instance, if both character widths are set to 8, then there is no difference of width between standard and wide characters, whether using \^x or not.

print("\^x6\^yathe curse\nof the\nstriped c🐱t")

Changing character rendering modes[]

The following special commands describe modes that change how characters are rendered. Each mode is either on or off. To enable, use the special command: \^i To disable, use - before the command: \^-i

  • \^w : Wide. Doubles the width.
  • \^t : Tall. Doubles the height.
  • \^= : Stripey. When wide or tall, only even pixels are rendered.
  • \^p : Pinball. Equivalent to wide, tall, and dotty.
  • \^i : Inverted. The foreground color is used as the background, and vice versa.
  • \^b : Bordered. Text has left and top padding. (On by default.)
  • \^# : Solid background. The default is a transparent background.

Modes can be combined: \^w\^t renders wide and tall characters.

Drawing one-off characters[]

You can specify a custom 8x8 character to be printed inline. Character data is specified either in hexadecimal (simpler) or raw binary data (more compact).

The data format is the same as that of custom fonts - each byte specifies a row of 8 pixels, with the bits in each byte being printed from the least significant bit on the left to the most significant on the right.

  • \^.<8 raw binary characters ("\0" for 0x00)>
  • \^:<16 hexadecimal characters ("00" for 0x00)>
-- print a cat
?"\^:447cb67c3e7f0106"
?"\^.D|へ|>○\1\6" -- warning: requires entering D in punycode mode (ctrl+p)

Poking memory[]

You can poke data to memory from within print:

  • \^@<address, 4 hexadecimal characters><N, 4 hexadecimal characters><N raw binary characters>
  • \^!<address, 4 hexadecimal characters><raw binary characters till end of string>

In both cases, the raw data encoded by the binary characters is poked into the address.

Audio commands[]

The \a control code triggers sound effects during printing. Unlike other control codes, \a can be followed by any number of characters describing the sound effects to play. To end the sequence, use a space. This space character is not printed.

To produce a simple beep, use \a without arguments:

print("\a alert: something happened")

To play a sound effect, provide the SFX number in decimal as the sole argument. Notice that the SFX number is in decimal (from 0 to 63), while other audio commands below use a single-character 0-9 a-z parameter value.

-- plays sfx 13, followed by text
print("\a13 alert: something wild happened")

You can describe an entire sound effect with a string of parameters to the audio command, including notes, instruments, effects, and more. This overwrites one of the SFX slots before playing the sound. If you provide an SFX number followed by a string, it will be written to that SFX slot, and can be played again by a subsequent code referencing the number. (It is written to RAM, not to the cart itself, and will not appear in the SFX editor.) If you do not specify an SFX number, PICO-8 will attempt to choose an unused slot between 60 and 63.

print "\aceg"          -- arpeggiated major triad

print "\a13ceg"        -- store in sfx 13 then play

Two sound effect parameters are set at the beginning of the string, because they apply to the full effect:

  • s P0: the sfx speed (Default: 4)
  • l P0 P1: loop start and end points (Default: 0, 0)

The rest of the string describes up to 32 notes, with optional codes to change the instrument, volume, and effect used for subsequent notes.

A note is a letter between a and g, followed by an optional # (sharp) or - (flat), and an optional octave number between 1 and 4.

print "\ace-g"   -- arpeggiated minor triad

To change settings for subsequent notes:

  • i P0: The instrument. The default is 5.
  • v P0: The volume. The default is 5.
  • x P0: The effect. The default is 0 (no effect).
  • < or >: Decrease or increase the previously set volume by one.

For example, to play a fast (speed 4), staccato (effect 5) arpeggio starting at C1:

print "\as4x5c1egc2egc3egc4"

Tip: Like all PICO-8 sound and music, sounds play in the background while printing continues. You can use the frame skipping special command to add delays to printing to wait for sound effects, like so:

print("you win!\as4x5c1egc2egc3egc4 \^4\ncongratulations!")

You can also play multiple sounds simultaneously by printing two separate audio commands without a delay between them, up to four simultaneous sounds (using the four sfx channels):

print("you win!\asfcdefg \asfefgab \^5\ncongratulations!")

PICO-8 uses default behaviors for characters and parameters in audio strings that are invalid or out of range, as follows:

  • When a note or setting code is expected, an invalid character is treated as a C note. A subsequent accidental or octave number is recognized.
    • ?"\asqc2def@fedc"
    • ?"\asqc2def@3fedc"
    • ?"\asqc2def@#3fedc"
  • When a setting parameter code is out of range, it behaves as the lowest value in the range.
    • ?"\as[c2defgfedc"
  • Octaves 1 through 4 are officially supported, and octaves 0 and 5 are also recognized. Octave numbers outside the range 0-5 are treated as invalid note characters, i.e. as C notes.
    • ?"\aszc5dee6dc" (caution: obnoxiously high pitched)
    • ?"\aszc0dee0dc"
  • Octave 5 only supports notes C, D, and E. All notes above E in octave 5 are treated as E5.
    • ?"\aszc5defgab" (caution: obnoxiously high pitched)
  • An audio pattern can contain at most 32 notes. A pattern that contains 32 notes will ignore the next character as if it were a space terminator, and subsequent characters are not considered part of the audio pattern.
    • ?"\as9c1defgabc2b1agfedc1defgabc2b1agfedc1defgggg" plays notes to the final F, ignores one g, then prints ggg.


Decoration characters[]

The control character \v can be used to decorate the last printed character with another character at a given offset, without needing to otherwise manage the cursor position. After the decorating character is printed, the previous cursor position is restored.

The format is \v P0 char, where P0 is a number giving the desired offset, and char is any character to print at that offset (relative to the previous printed character).

The offset has x packed into the lowest 2 bits, and starts (-2,-8) in reading order. So 3 means (+1, -8), 4 means (-2, -7) and so on.

For example, to write "café!", using a comma to draw the accute accent:

print"\ncafe\vb,!"

In this case P0 is 'b', which is read as the number 11. So the comma is drawn at:

x = (11%4)-2 = 1
y = (11\4)-8 = -6


Custom fonts[]

PICO-8 supports a single custom font in addition to its default font. Your program must load the font data starting at RAM address 0x5600, including a header that describes attributes of the font. With this font in memory, you enable the font with the control character \014. Subsequent characters are printed in the custom font. To return printing to the default font, print code \015. As with other effects, printing returns to the default font at the end of the print().

Tip: Drawing and storing font data in code can be challenging, so there's a tool to make this easier. Type load #font_snippet to load this tool into PICO-8. The font snippet tool lets you draw your font in the sprite editor, then export it as a single compact poke() statement that loads the entire font into memory. Paste this code snippet into your cart, then use the control codes to activate it.

Font memory[]

The custom font memory layout consists of 8 bytes per character for all 256 characters in the P8SCII character set, for a total of 2048 bytes. Each character is an 8 x 8 bitfield. Bits are drawn left to right starting with the least significant bit. For examples:

  0x01    #_______
  0x15    #_#_#___
  0x80    _______#
  0xfe    _#######

Character 0 is never printed, so its bytes (starting at address 0x5600) are used as the header for the font.

  • 0x5600: Character width in pixels. Can be more than 8, but only 8 pixels are drawn. The print cursor advances horizontally by this amount for each character.
  • 0x5601: Character width for character 128 and above.
  • 0x5602: Character height in pixels. The print cursor advances vertically by this amount for each newline.
  • 0x5603: Draw offset x, in pixels. This is an offset from the cursor position where the character is drawn. The new cursor position does not include this offset.
  • 0x5604: Draw offset y, in pixels.

The following simple example defines a custom font of size 8 x 8 with no draw offset, redefines character #16 (address 0x5680-0x5687) as a triangle shape, prints the \014 control code to switch to the custom font, then prints three #16 characters (\016). It then disables the custom font (\015) to print a word in the default font.

poke(0x5600, 8)    -- char width
poke(0x5601, 8)    -- char width for high cars
poke(0x5602, 8)    -- char height
poke(0x5603, 0)    -- draw x offset
poke(0x5604, 0)    -- draw y offset

poke(0x5680, 1)    -- #_______
poke(0x5681, 3)    -- ##______
poke(0x5682, 7)    -- ###_____
poke(0x5683, 15)   -- ####____
poke(0x5684, 31)   -- #####___
poke(0x5685, 63)   -- ######__
poke(0x5686, 127)  -- #######_
poke(0x5687, 255)  -- ########

cls()
print("\014\016\016\016\015 tada\n\n")

Note: While there is memory space in font memory for defining glyphs for P8SCII codes 0-15, these codes are reserved for the P8SCII control codes. Printing these codes will have their control code effects and never print the glyphs.


Terminating printing[]

When print() encounters the \0 control code, it stops printing.

print("sorry you're breaking up i'm going into a tun\0nel")

Note: Without coordinates, print() normally prints a newline at the end of the string. When the string contains the null terminator code, print() will not print the newline. In the PICO-8 console, this has the effect of not printing the string at all, unless followed by another print() statement.

print("abc\0def"); print("ghi")


Repeating characters[]

The \* control code takes a numeric argument and repeats the next character that many times.

print("\*3a")   -- prints "aaa"


Default attributes[]

Control codes modify printing attributes during the printing of a string. When print() completes, it resets these attributes back to their default settings. (As noted above, cursor position and foreground color are exceptions: these are properties of the draw state.)

You can modify the default settings of these attributes so that every print() starts with these settings. To modify the settings, poke() new values into memory addresses 0x5f58 through 0x5f5b.

Default rendering modes[]

Address 0x5f58 is a bitfield for the character rendering modes. Bit 0x1 enables the rendering modes, and must be set to 1 for any of the modes to take effect. These modes are:

  • 0x1: Enable
  • 0x2: Padding
  • 0x4: Wide
  • 0x8: Tall
  • 0x10: Solid background
  • 0x20: Invert
  • 0x40: Dotty
  • 0x80: Use custom font

For example, to enable "pinball" text by default for all printing:

-- set enable, padding, wide, tall, inverted, dotty
poke(0x5f58, 0x1 | 0x2 | 0x4 | 0x8 | 0x20 | 0x40)

print("on sale now!")
print("how do i turn this off?")

-- clear all flags, including enable
poke(0x5f58, 0)

print("phew!")

Default sizes and offsets[]

Defaults for character sizes (cursor travel), the tab width, and the draw offsets can be changed with addresses 0x5f59 through 0x5f5b.

Each value is 4 bits wide (a "nibble"), and occupies either the low nibble (0x8, 0x4, 0x2, 0x1) or the high nibble (0x80, 0x40, 0x20, 0x10). The value is stored most significant bit first.

  • 0x5f59 low nibble: Character width
  • 0x5f59 high nibble: Character height
  • 0x5f5a low nibble: Character width for codes above 128
  • 0x5f5a high nibble: Tab stop width, in increments of 4 pixels (4-64)
  • 0x5f5b low nibble: Draw offset x, in pixels
  • 0x5f5b high nibble: Draw offset y, in pixels
-- set default draw offset to y of 3 pixels, x of 2 pixels
poke(0x5f5b, 0x32)
print("shifted\n\n")

-- update the draw offset of y to 1 pixel, keeping x at the previous setting
poke(0x5f5b, 0x10 | (peek(0x5f5b) & 0x0f))
print("shifted\n\n")
Advertisement