TIC-80 The Missing Manual



TIC-80 is a tiny computer which you can use to make, play, and share tiny games. Built-in development tools include code, sprite, map and sound editors which along with the command line tools, provide everything you need to create a mini retro game. Once your game is finished you can export it to a cartridge file, which can be stored and uploaded to the TIC-80 website. Alternatively, it can be packed into a stand-alone player that works on all popular platforms and can be distributed as you wish. To make a retro styled game, the whole process of creation takes place under some technical limitations: 240x136 pixels display, a 16 color palette, 256 8x8 color sprites, 4 channel sound, etc.

Display 240x136 pixels, 16-color palette Input 4 gamepads with 8 buttons / mouse / keyboard Sprites 256 8x8 foreground sprites and 256 8x8 background tiles Map 240x136 cells, 1920x1088 pixels (2408 x 1368) Sound 4 channels (with editable waveform envelopes) Code 64KB of compressed code *Bankswitching Up to 8 banks in cart (PRO version only)


Main functions / Callbacks


TIC is the ‘main’ function and must be present in every program. It takes no parameters and is called sixty times per second (60fps).


– script: lua function TIC() – Put your stuff here end


SCN() allows you to execute code between the drawing of each scan line, for example, to manipulate the palette.


function SCN(line) – your code here end


OVR() is called on every frame. It draws on a separate layer and can be used together with SCN() to create separate background or foreground layers and other visual effects.

Syntax: function OVR() –Draw foreground end



btn [id: 0..31] -> pressed



This function allows you to read the status of one of the buttons attached to TIC. The function returns true if the key with the supplied id is currently in the pressed state. It remains true for as long as the key is held down. If you want to test if a key was just pressed, use btnp instead.

Action P1ID P2ID P3ID P4ID Up 0 8 16 24 Down. 1. 9. 17. 25 Left. 2. 10. 18. 26 Right. 3. 11. 19. 27 A. 4 12. 20. 28 B. 5. 13. 21. 29 X. 6. 14. 22. 30 Y. 7. 15. 23. 31


btnp [[id: 0..31], [hold], [period] ] -> pressed (but wasn’t pressed in previous frame)

This function allows you to read the status of one of TIC’s buttons. It returns true only if the key has been pressed since the last frame.

You can also use the optional hold and period parameters which allow you to check if a button is being held down. After the time specified by hold has elapsed, btnp will return true each time period is passed if the key is still down. For example, to re-examine the state of button ‘0’ after 2 seconds and continue to check its state every 1/10th of a second, you would use btnp(0, 120, 6). Since time is expressed in ticks and TIC runs at 60 frames per second, we use the value of 120 to wait 2 seconds and 6 ticks (ie 60/10) as the interval for re-checking.



key [code: 1..65] -> pressed *** KEYCODES ***

01 = A 02 = B 03 = C 04 = D 05 = E 06 = F 07 = G 08 = H 09 = I 10 = J 11 = K 12 = L 13 = M 14 = N 15 = O 16 = P 17 = Q 18 = R 19 = S 20 = T 21 = U 22 = V 23 = W 24 = X 25 = Y 26 = Z

27 = 0 28 = 1 29 = 2 30 = 3 31 = 4 32 = 5 33 = 6 34 = 7 35 = 8 36 = 9


48 = SPACE 49 = TAB


54 = PAGEUP 55 = PAGEDOWN 56 = HOME 57 = END 58 = UP 59 = DOWN 60 = LEFT 61 = RIGHT

62 = CAPSLOCK 63 = CTRL 64 = SHIFT 65 = ALT

.-----------------------------------------------------------------------------------------.        .----------------------.
|  `  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  0  |  -  |  =  |  Backsps  |        |  Ins  |  Home | PgUp |
|-----------------------------------------------------------------------------------------|        |----------------------|
|  Tab   |  Q  |  W  |  E  |  R  |  T  |  Y  |  U  |  I  |  O  |  P  |  [  |  ]  |   \    |        |  Del  |  End  | PgDn |
|-----------------------------------------------------------------------------------------|        '----------------------'
|  CapsLck  |  A  |  S  |  D  |  F  |  G  |  H  |  J  |  K  |  L  |  ;  |  '  |    Enter  |
|-----------------------------------------------------------------------------------------|                .-------.
|  Shift       |  Z  |  X  |  C  |  V  |  B  |  N  |  M  |  ,  |  .  |  /  |       Shift  |                |   Up  |
|-----------------------------------------------------------------------------------------|        .----------------------.
|  Ctrl  |  Alt  |                                                       |  Alt  |  Ctrl  |        |  Left |  Down | Rght |
'-----------------------------------------------------------------------------------------'        '----------------------'


keyp code hold period



This function returns true if the given key is pressed but wasn’t pressed in the previous frame. Refer to btnp for an explanation of the optional hold and period parameters


mouse -> x y left middle right scrollx scrolly

This function returns the mouse coordinates and a boolean value for the state of each mouse button, with true indicating that a button is pressed.


title: mouse demo– author: Raidez– script: lua– input: mouse

t=0 x=104 y=24 function TIC() mx,my,md=mouse() –get x,y and pressed

    if md then





clip [x y w h]

This function limits drawing to a clipping region or ‘viewport’ defined by x,y,w,h. Things drawn outside of this area will not be visible.

Calling clip() with no parameters will reset the drawing area to the entire screen.




This function clears the entire screen using the color argument. If no parameter is passed, index 0 of the palette is used. The function is usually called inside TIC(), but isn’t mandatory. If you’re drawing to the entire screen, for example with sprites, the map or primitive shapes, there’s no need to clear the screen with cls() beforehand. Tip: You can create some interesting effects by not calling cls() or calling it repeatedly it to “flash” the screen when some special event occurs. You can also supply a color index above 15 to see some interesting fill patterns!



circ x y radius color

This function draws a filled circle of the desired radius and color with its center at x, y. It uses the Bresenham algorithm.



circ x y radius color

Draws the circumference of a circle with its center at x, y using the radius and color requested.



line x0 y0 x1 y1 color


Draws a straight line from point (x0,y0) to point (x1,y1) in the specified color.



pix x y [color] -> color

This function can read or write pixel color values. When called with a color parameter, the pixel at the specified coordinates is set to that color. Calling the function without a color parameter returns the color of the pixel at the specified position.



rect x y w h color


This function draws a filled rectangle of the desired size and color at the specified position. If you only need to draw the border or outline of a rectangle (if not filled) see rectb




*rectb x y w h color


This function draws a one pixel thick rectangle border at the position requested. If you need to fill the rectangle with a color, see rect instead.



*tri x1 y1 x2 y2 x3 y3 color

This function draws a triangle filled with * color *, using the supplied vertices.


*textri x1 y1 x2 y2 x3 y3 u1 v1 u2 v2 u3 v3 [use_map=false] [colorkey=-1]

It renders a triangle filled with texture from image ram or map ram

Program / Interrupts


Interrupts program execution and returns to the console when the TIC function ends.


Reset game to initial state (0.60) Resets the cartridge. To return to the console, see the exit function.


** Milliseconds ** elapsed since game start.

This function returns the number of ** milliseconds ** elapsed since the cartridge began execution. * Useful for keeping track of time, animating items and triggering events. *


The current unix timestamp in ** seconds. **

This function returns the number of ** seconds ** elapsed since January 1st, 1970. * Useful for creating persistent games which evolve over time between plays. *


*trace msg [color]

This is a service function, useful for debugging your code. It prints the message parameter to the console in the (optional) color specified.

** tips: ** * The * Lua * concatenator for strings is .. (two points) * Use console * cls * command to clear the output from trace

Sprite / Map


Returns true if the specified flag of the sprite is set.

fget index flag



fset index flag bool


index : sprite index flag : index of flag (0-7) *bool : What state to set the flag, true or false


Each sprite has eight flags which can be used to store information or signal different conditions. For example, flag 0 might be used to indicate that the sprite is invisible, flag 6 might indicate that the flag should be draw scaled etc.


map [x=0 y=0] [w=30 h=17] [sx=0 sy=0] [colorkey=-1] [scale=1] [remap=nil]

The map consists of cells of 8x8 pixels, each of which can be filled with a sprite using the map editor. The map can be up to 240 cells wide by 136 deep. This function will draw the desired area of the map to a specified screen position. For example, map(5,5,12,10,0,0) will draw a 12x10 section of the map, starting from map co-ordinates (5,5) to screen position (0,0).



mget x y -> id


returns the sprite id at the given x and y map coordinate


mset x y id

This function will change the tile at the specified map coordinates. By default, changes made are only kept while the current game is running. To make permanent changes to the map, see sync.



spr id x y [colorkey=-1] [scale=1] [flip=0] [rotate=0] [w=1 h=1]

Draw sprite by ID, can be rotated or flipped

Draws the sprite number index at the x and y coordinate. You can specify a colorkey in the palette which will be used as the transparent color or use a value of -1 for an opaque sprite. The sprite can be scaled up by a desired factor. For example, a scale factor of 2 means an 8x8 pixel sprite is drawn to a 16x16 area of the screen. You can flip the sprite where: * 0 = No Flip * 1 = Flip horizontally * 2 = Flip vertically * 3 = Flip both vertically and horizontally When you rotate the sprite, it’s rotated clockwise in 90° steps: * 0 = No rotation * 1 = 90° rotation * 2 = 180° rotation * 3 = 270° rotation You can draw a composite sprite (consisting of a rectangular region of sprites from the sprite sheet) by specifying the w and h parameters (which default to 1).



This function will draw text to the screen using sprites from the foreground sprite-sheet for the font. More specifically, sprite ID#256 is used for ASCII code 0, #257 for code 1 and so on. The character ‘A’ has the ASCII code 65 so will be drawn using the sprite with ID#321 (256+65). See the example below or check out the In-Browser Demo

To simply print text to the screen using the default font, see print. To print to the console, refer to trace


text : any string to be printed to the screen x : x coordinate where to print the text y : y coordinate where to print the text colorkey : the colorkey to use as transparency. char width : Width of characters to use for spacing, in pixels char height : Height of characters to use for multiple line spacing, in pixels. fixed : a flag indicating whether to fix the width of the characters, by default is not fixed scale : font scaling



*print text [x=0 y=0] [color=15] [fixed=false] [scale=1] [smallfont=false] -> width


This will simply print text to the screen using the font defined in config. When set to true, the fixed width option ensures that each character will be printed in a ‘box’ of the same size, so the character ‘i’ will occupy the same width as the character ‘w’ for example. When fixed width is false, there will be a single space between each character. Refer to the example for an illustration. * To use a custom rastered font, check out font. * To print to the console, check out trace.




memcpy toaddr fromaddr len

This function allows you to copy a continuous block of TIC’s 64k RAM from one address to another. Addresses are specified are in hexadecimal format, values are decimal.

###parameters * toaddr : the address you want to write to * fromaddr : the address you want to copy from * len : the length of the memory block you want to copyDescription:


memset addr val len

This function allows you to set a continuous block of any part of TIC’s RAM to the same value. The address is specified in hexadecimal format, the value in decimal.


peek addr -> val (byte)

This function allows to read the memory from TIC. It’s useful to access resources created with the integrated tools like sprite, maps, sounds, cartridges data? Never dream to sound a sprite? Address are in hexadecimal format but values are decimal. To write to a memory address, use poke.


Output: * val : the value read from the addr parameter. Each address stores a byte, so the value will be an integer from 0 to 255.



peek4 addr4 -> val4

This function enables you to read values from TIC’s RAM. The address should be specified in hexadecimal format. addr4 : any address of the 80K RAM byte you want to read, divided in groups of 4 bits (nibbles). Therefore, to address the high nibble of position 0x2000 you should pass 0x4000 as addr4, and to access the low nibble (rightmost 4 bits) you would pass 0x4001. val4 : the 4-bit value (0-15) read from the specified address.



pmem index:0..255 [val] -> val

This function allows you to save and retrieve data in one of the 256 individual 32-bit slots available in the cartridge’s persistent memory. This is useful for saving high-scores, level advancement or achievements. The data is stored as unsigned 32-bit integers (from 0 to 4294967295).



poke addr val

This function allows you to write a single byte to any address in TIC’s RAM. The address should be specified in hexadecimal format, the value in decimal.



poke4 addr4 val


This function allows you to write to the virtual RAM of TIC. It differs from poke in that it divides memory in groups of 4 bits. Therefore, to address the high nibble of position 0x4000 you should pass 0x8000 as addr4, and to access the low nibble (rightmost 4 bits) you would pass 0x8001. The address should be specified in hexadecimal format, and values should be given in decimal.



Copy modified sprites/map to the cartridge

*sync [mask=0] [bank=0] [tocart=false]

The pro version of TIC-80 contains 8 memory banks. To switch between these banks, sync can be used to either load contents from a memory bank to runtime, or save contents from the active runtime to a bank. The function can only be called once per frame.



music [track=-1] [frame=-1] [row=-1] [loop=true] [sustain=false]

This function starts playing a track created in the Music Editor. Call without arguments to stop the music.



sfx id [note] [duration=-1] [channel=0] [volume=15] [speed=0]

This function will play the sound with id created in the sfx editor. Calling the function with id set to -1 will stop playing the channel. The note can be supplied as an integer between 0 and 95 (representing 8 octaves of 12 notes each) or as a string giving the note name and octave. For example, a note value of ‘14’ will play the note ‘D’ in the second octave. The same note could be specified by the string ‘D-2’. Note names consist of two characters, the note itself (in upper case) followed by ‘-’ to represent the natural note or ‘#’ to represent a sharp. There is no option to indicate flat values. The available note names are therefore: C-, C#, D-, D#, E-, F-, F#, G-, G#, A-, A#, B-. The octave is specified using a single digit in the range 0 to 8. The duration specifies how many ticks to play the sound for; since TIC-80 runs at 60 frames per second, a value of 30 represents half a second. A value of -1 will play the sound continuously. The channel parameter indicates which of the four channels to use. Allowed values are 0 to 3. Volume can be between 0 and 15. Speed in the range -4 to 3 can be specified and means how many ‘ticks+1’ to play each step, so speed==0 means 1 tick per step.