The retro game development engine for Go, inspired by Pico-8 and powered by Ebitengine.

  • By Jacek Olszak
  • Last update: Dec 15, 2022
  • Comments: 10


Go Reference codecov Project Status: Active – The project has reached a stable, usable state and is being actively developed.

The retro game development engine for Go, inspired by Pico-8 and powered by Ebitengine.


Is this a new fantasy console?

No, it's not. It's rather a game development library with some additional tools (like a console) which make it simple (and fun!) to write retro games in Go.

What is a retro game?

It's a game that resembles old 8-bit/16-bit games. This usually means:

  • (extremely) Low resolution (like 128x128 pixels)
  • Limited number of colors (like 16)
  • Very small number of assets (like 256 sprites, map having up to 8K tiles)
  • Simple rules (opposite to Paradox grand strategy games)
  • Sound effects and music made using predefined synth instruments and effects

What similarities does Pi have with Pico-8?

  • Most API function names are similar and behave the same way.
  • Screen resolution is small, and the number of colors is limited. Although in Pi you can change the resolution and palette.
  • You have one small sprite sheet.

Why would I use it?

Because it's the easiest way to write a game in Go. IMHO ;)

Is Pi ready to use?

Pi is under development. Only limited functionality is provided. API is not stable. See roadmap for details.

How to get started?

  1. Install dependencies
  1. Create a new game using provided Github template.

See also examples directory and documentation.



  • 1

    Add AudioStream abstraction to ebitengine package

    Add AudioStream abstraction to ebitengine package

    AudioStream is an abstraction used by ebitengine back-end to consume audio stream generated by the game. The stream will be played back to the user. By default, [pi.AudioSystem] is used. Game developers could use a different audio system though. In such case they could set the AudioStream variable to their own implementation.

    This commit adds AudioSystem placeholder to pi package which will eventually generate audio stream from sound effects. This work will be done in next PRs.

  • 2

    Set screen size limit

    Limit the maximum screen size to 65536 (64KB) for following reasons:

    • bigger screens are not good for pixel-perfect programming
    • the more pixels, the longer it takes to create game assets
    • PI uses CPU for screen manipulation, which means it is slow for high resolutions such as FullHD or 4K
  • 3

    Add PixMap struct

    PixMap is a generic data structure for manipulating any kind of pixel data - screen, sprite-sheet etc.

    PixMap uses a single byte (8 bits) for storing single color/pixel. This means that max 256 colors can be used.

    PixMap can also be used for maps which not necessary contain pixel colors, such as world map (as long as only 256 different tiles are used).

    This commit replaces pi.Screen and pi.SpriteSheet with pi.PixMap.

    PixMap provides also new methods:

    • Copy - copy PixMap fragment to another PixMap at specific location
    • Merge - customizable variant of Copy. User can provide his own merge function which will be used instead of directly copying pixels.
    • Foreach - run code line by line on selected PixMap fragment
    • Pointer - low-level method for high-performance processing
  • 4

    Add MinInt,MaxInt and MidInt functions

    These functions calculate minimum, maximum and middle numbers from integer parameters. They work will all integer parameters such as byte, int, uint etc.

  • 5

    Make low-level API safer to use

    mem package is unsafe to use. User might set screen size without updating data slice. Same for sprite-sheet.

    Also, mem package duplicates a lot information which might be confusing for user (for example which package mem or pi the source of truth?)

    Also, functions like pi.Boot() or pi.Run() are hard to understand. User has to remember than after specifying the new screen size he has to boot the game again.

    This change is a huge one. It removes mem package completely and instead it introduces new functions:

    • SetScreenSize
    • UseEmptySpriteSheet
    • SetCustomFontWidth
    • SetCustomFontSpecialWidth
    • SetCustomFontHeight
  • 6

    Remove fmt dependency from vm package

    vm package is using fmt.Sprintf to print RGB as hex. This dependency is a lot of code and should not be a part of package imported practically by every package.

  • 7

    Move Snap() function to new `snap` package

    Rename to snap.Take().

    This function imports a lot of dependencies (such as os and image/*). Most games will not use it, so the function should not be a part of core pi package.

  • 8

    Move State*** functions to new state package

    Code for managing state information is big and imports a lot of dependencies (json and fmt). Most games will not store state, therefore this code should not be place in a core package. This could reduce binary size.

  • 9

    Remove Cursor and CursorReset and add custom font

    Remove Cursor and CursorReset

    Print now accepts mandatory x,y position instead. Cursor, CursorReset functions were removed.

    It still possible to print multi-line text by using special '\n' character inside the string text.


    Add custom font Custom font could be used together with system font.

    This commit also adds pi.LoadFontData which could be used to load font from PNG file into another font instance.

  • 10

    Implement keyboard

    Virtual keyboard contains 71 buttons inspired by US keyboard layout:

    	ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
    	`  1  2  3  4  5  6  7  8  9  0  -  =  <--
    	TAB Q  W  E  R  T  Y  U  I  O  P  [   ]  \
    	CAP  A  S  D  F  G  H  J  K  L  ;  ' ENTER
    	SHIFT Z  X  C  V  B  N  M  ,  .  /    ↑
    	CTRL ALT        SPACE              ←  ↓  →