{"id":13337721,"url":"https://github.com/elgopher/pi","last_synced_at":"2025-12-25T12:11:32.528Z","repository":{"id":49343257,"uuid":"515452970","full_name":"elgopher/pi","owner":"elgopher","description":"The retro game development engine for Go, inspired by Pico-8 and powered by Ebitengine.","archived":false,"fork":false,"pushed_at":"2024-04-01T17:28:47.000Z","size":481,"stargazers_count":29,"open_issues_count":5,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-01T18:38:52.562Z","etag":null,"topics":["ebiten","ebitengine","game","game-development","game-engine","game-library","gamedev","go","golang","pi","pico-8","pico8","pixel-perfect","pyxel","tic-80"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elgopher.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null}},"created_at":"2022-07-19T05:54:18.000Z","updated_at":"2024-03-12T12:41:41.000Z","dependencies_parsed_at":"2023-10-02T23:26:51.905Z","dependency_job_id":"60ec5f18-71b9-40e9-a1e3-41dfa06ce56c","html_url":"https://github.com/elgopher/pi","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Fpi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Fpi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Fpi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elgopher%2Fpi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elgopher","download_url":"https://codeload.github.com/elgopher/pi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213069710,"owners_count":15532844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ebiten","ebitengine","game","game-development","game-engine","game-library","gamedev","go","golang","pi","pico-8","pico8","pixel-perfect","pyxel","tic-80"],"created_at":"2024-07-29T19:14:56.246Z","updated_at":"2025-12-25T12:11:32.523Z","avatar_url":"https://github.com/elgopher.png","language":"Go","readme":"# pi \u003cimg src=\"docs/logo.svg\" align=\"right\" style=\"width: 10%\"/\u003e\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/elgopher/pi.svg)][pi-godoc]\n[![codecov](https://codecov.io/gh/elgopher/pi/branch/master/graph/badge.svg)][pi-codecov]\n[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)][repostatus-active]\n[![Go Report Card](https://goreportcard.com/badge/github.com/elgopher/pi)](https://goreportcard.com/report/github.com/elgopher/pi)\n\n## Table of Contents\n\n- [Introduction](#introduction)\n- [What defines the retro games made with Pi?](#what-defines-the-retro-games-made-with-pi)\n- [Why Pi?](#why-pi)\n- [How to get started?](#how-to-get-started)\n- [How does it work?](#how-does-it-work)\n- [FAQ](#faq)\n- [Attributions](#attributions)\n\n## Introduction\n\nPi is a game engine for creating retro games for modern computers. Its goal is to limit possibilities — to spark creativity and increase the chance of actually finishing your game. Too much freedom often leads to overly ambitious and never-ending projects. Pi was inspired by [Pico-8][pico-8] and is powered by [Ebitengine][ebitengine].\n\nAlthough Pi was inspired by fantasy consoles, it is **not** one itself. It doesn't emulate a fictional machine. Instead, it's a real Go library with dev-tools that make it simple (and fun!) to build retro games that run natively on modern hardware.\n\n[![Snake game example](docs/screenshot-snake.png)](_examples/snake)\n\n## What defines the retro games made with Pi?\n\nThey resemble games from 8-bit and 16-bit computers, because:\n* they run at (very) low resolutions — like 128×128 or 320×180\n* they use only 64 colors displayed on screen at once\n* they use graphics rendered directly by the CPU — just like in early home computers\n* they use sound effects and music made from short, looped audio samples. The audio output is generated by mixing 4 channels.\n* they work with limited resources — such as 256 sprites or tile maps with just a few thousand tiles\n* their code is short — thousands, not millions, of lines\n* they use game controllers with a small number of buttons\n\n## Why Pi?\n\nBecause it's probably the easiest and most fun way to write a game in Go. No complex engine setup. No boilerplate. Just write code and see things happen. Perfect for small projects, prototypes, jams — or simply to have fun.\n\n## How to get started?\n\n1. Install dependencies\n    * [Go 1.24+][go-downloads]\n    * If you are not on Windows, install additional dependencies for:\n        * [Linux](docs/install-linux.md)\n        * [macOS](docs/install-macos.md)\n\n2. Try examples from the [_examples](_examples) directory\n    * Run the Snake example directly:\n      ```bash\n      go run github.com/elgopher/pi/_examples/snake@HEAD\n      ```\n    * Or clone the Pi repository and modify the example:\n      ```bash\n      git clone https://github.com/elgopher/pi\n      cd pi/_examples/snake\n      # edit main.go to experiment\n      go run .\n      ```\n\n3. Create a new game\n    * Create a new Go module and add Pi as a dependency:\n      ```bash\n      mkdir mygame\n      cd mygame\n      go mod init mygame\n      go get github.com/elgopher/pi@latest\n      ```\n   * Create main.go:\n      ```go\n      package main\n         \n      import (\n         \"github.com/elgopher/pi\"          // import pi core package\n         \"github.com/elgopher/pi/picofont\" // import very small pico-8 font\n         \"github.com/elgopher/pi/piebiten\" // import backend\n      )\n   \n      func main() {\n         pi.SetScreenSize(47, 9) // set custom screen size\n         pi.Draw = func() {      // draw will be executed each frame\n            picofont.Print(\"HELLO WORLD\", 2, 2)\n         }\n         piebiten.Run() // run backend\n      }\n      ```\n   * Tidy go.mod file after importing Pi packages\n      ```bash\n      go mod tidy\n      ```\n   * Run the game:\n      ```bash\n      go run .\n      ```\n\n\n4. Explore further\n    * Read the rest of this README.md\n    * Check out the [godoc documentation][pi-godoc]\n\n## How does it work?\n\nPi is designed to make writing a game as simple as possible — even if you've never made one before.  \nIt gives you just a few core concepts and keeps things minimal, so you can focus on making something fun.\n\n---\n\n### Game loop\n\nPi runs your game in a loop. In each frame, it calls two functions you define:\n\n* `pi.Update` — where you put your game logic, e.g. handling input.  \n* `pi.Draw` — where you put your rendering code. It runs right after `pi.Update`.\n\nBy default, Pi runs these functions 30 times per second, but this is configurable.\n\n---\n\n### Backend\n\nPi has a modular architecture that allows using different backends.  \nA backend is a low-level package that runs your game on different devices.  \n\nCurrently, the recommended backend is [piebiten](piebiten), which supports Windows, macOS, Linux, and more, using Ebitengine under the hood.\n\nHere's a minimal example that displays \"HELLO WORLD\" on a 47×9 pixel screen using the piebiten backend:\n\n```go\npackage main\n\nimport (\n   \"github.com/elgopher/pi\"          // core package\n   \"github.com/elgopher/pi/picofont\" // tiny Pico-8 font\n   \"github.com/elgopher/pi/piebiten\" // backend\n)\n\nfunc main() {\n   pi.SetScreenSize(47, 9) // set custom screen size\n   pi.Draw = func() {      // draw runs each frame\n      picofont.Print(\"HELLO WORLD\", 2, 2)\n   }\n   piebiten.Run()          // run the backend\n}\n````\n\nWhen Pi opens a window for your game, it automatically adjusts the window size to match your monitor's resolution. Since modern monitors have much higher resolutions (e.g. 1920×1080 or even 3840×2160), Pi needs to scale up the game screen. Each game pixel is multiplied an integer number of times (integer scaling). This ensures that the game screen always stays true to its original pixel-perfect look without any distortion.\n\n---\n\n### Game screen\n\nPi gives you a small, low-resolution pixel canvas to draw on. It's like an old-school screen: you can set pixels, draw lines, rectangles, sprites, and text. The limited resolution encourages you to focus on clear shapes and designs.\n\nEach pixel on the game screen has (x, y) coordinates and a `pi.Color`. `pi.Color` is a number from 0 to 63, letting you use up to 64 colors on screen at once. Coordinate (0,0) is the top-left corner of the screen.\n\nPi does not impose any fixed screen size — you can choose resolutions like 128×128 or 320×180. However, there's a limit on the total number of pixels: 128 KB (131,072 pixels). It's recommended to start with a low resolution for your first game, such as 128×128.\n\n---\n\n### Color palette\n\nPi uses a game-defined, configurable `pi.Palette` which maps each `pi.Color` to an RGB value. For example, by default color 0 is black (0x000000), and color 7 is white (0xFFF1E8).\n\nYou choose your game's palette, but you're limited to 64 colors. That may seem small, but for low-resolution pixel-art it's usually plenty.\nThe palette can be changed during the game, but changes will appear only when rendering the frame at the end of the update cycle.\n\n---\n\n### Canvas, sprites, and blitting\n\n`pi.Canvas` is a 2D structure storing color values. The game screen itself is a Canvas. Your game can not only draw pixels on a Canvas but also read them back.\n\nThis makes it possible to copy pixels from one Canvas to another — for example, you can load a PNG file into a Canvas and then copy (blit) parts of it onto the game screen.\n\nThese source images (PNG files with your art) are typically called **sprite sheets**. Pi can decode them into Canvases and help you define sprites that you then blit onto the screen.\n\n---\n\n### Keyboard, mouse, and gamepad input\n\nPi lets you check the state of buttons on various input devices. To make sure games work across different hardware, Pi defines a subset of buttons that exist on most modern keyboards, mice, and gamepads.\n\nPi also tries to offer only the kinds of input that were typical in the 16-bit era. For example, mice had just two buttons, and gamepads had only simple digital (on/off) buttons — no analog sticks or triggers.\n\nFor handling input devices, you can use these packages: [pikey](pikey), [pimouse](pimouse), and [pipad](pipad).\n\n---\n\n### Audio\n\nPi audio system is inspired by the Paula audio chip used in Amiga computers.\n\nIn Pi, sound is generated in 4 independent channels, which are then mixed to stereo output: channels 0 and 3 are mixed to the left speaker, and channels 1 and 2 to the right.\n\nEach channel plays a single audio sample at a time, which means you can play 4 different samples simultaneously. A channel, in addition to holding the current sample, also stores parameters such as pitch, volume, and loop, which affect how the sound is generated. These parameters can be updated in real-time to play sound effects and music.\n\nPi only supports samples encoded in 8-bit mono PCM format. \n\nYou can control audio generation with the [piaudio](piaudio) package.\n\n---\n\n### Concurrency\n\nMost of Pi's code is **not** thread-safe. This is an intentional design choice to significantly improve performance.  \nYou should not call Pi's API from any goroutine other than the one running your `pi.Update` and `pi.Draw` functions.\n\nYou can still create your own goroutines in your game, but they must not call any Pi functions or access Pi state (unless the package documentation explicitly says it's safe).\n\n---\n\n### Philosophy: Limitations Make It Fun\n\nPi intentionally limits:\n\n* screen resolution\n* color palette\n* number of audio channels\n\nThese constraints force you to be creative and keep things simple. It's easier to finish a game when you don't try to do everything at once.\nThe goal is to have fun, not get lost in complexity!\n\n## FAQ\n\n### Is Pi ready to use?\n\nYes — the core functionality is implemented and ready to use. Currently, the focus is on developer tools like [piscope](piscope).\n\nNote: Pi does not yet have high-level APIs for music playback. However, there is a low-level [piaudio](piaudio) API that can be used to create custom packages for playing, for example, [MOD][mod] and [XM][xm] modules.\n\n### What similarities does Pi have with Pico-8/Picotron on the API level?\n\n* Many core concepts are similar: game loop, drawing sprites and shapes, printing text, clipping, camera movement, palette swapping, color tables, and handling input.\n* The screen resolution is small and the number of colors is limited — just like in Pico-8.  \n  However, in Pi you can freely change the resolution and customize the palette.\n\n### Can I use Pi in a game that already uses Ebitengine?\n\nYes! You can use the [piebiten](piebiten) package to integrate Pi with your existing Ebitengine project. For example, you can copy pixel data from `pi.Canvas` into an `ebiten.Image`.\n\n### What platforms do Pi games run on?\n\nPi runs on all platforms supported by Ebitengine. However, it is currently tested only on Windows, Linux, and web browsers.\n\n### Can I write my own backend for Pi instead of Ebitengine?\n\nYes! You can create a specialized backend that runs on unusual devices or is optimized for a specific architecture. For example, there's [piweb][piweb] — an experimental backend for web browsers. Its goal is to cut the size of the generated WASM program roughly in half, which can be important for small browser-based games.\n\n### How can I contribute to Pi's development?\n\nThe best way to help Pi grow is by creating your own packages that add new or improved features. Pi is designed so that anyone can extend it without needing to contribute code directly to the main Pi repository.  \nExamples of useful packages include:\n\n* developer tools that other programmers can run directly in their games\n* packages for generating sound\n* packages for drawing\n* new backends\n\n### What tools are recommended for making games with Pi?\n\nFirst of all, you'll need a good Go editor. I recommend GoLand (paid) or Visual Studio Code.\n\nFor creating sprites, I highly recommend [Aseprite][aseprite] — probably the best pixel-art editor ever made. It has tons of features, scripting support, and can export images with metadata. In general, try to use the same color indices in your graphics program and in your game code. It really simplifies game development. Aseprite is one of the tools that supports editing images with indexed colors.\n\nFor creating tile maps, I recommend [Tiled][tiled].\n\n### How can I persist game state or settings?\n\nPi itself doesn't include built-in save/load APIs. To store your game's progress or settings, you can use the external Go module [quasilyte/gdata][quasilyte-gdata].\n\n### I have more questions or found a bug. Where can I ask?\n\nPlease open an [Issue][issues] or start a [Discussion][discussions] on GitHub. Questions, ideas, bug reports, and contributions are all welcome!\n\n## Attributions\n\n* [picofont](picofont) package uses [original Pico-8 font][pico-8-faq] created by Zep - [CC-0 license][cc-0]\n* default palette is the [original Picotron palette][picotron-faq] created by Zep\n\n[aseprite]: https://www.aseprite.org/\n[cc-0]: https://creativecommons.org/publicdomain/zero/1.0/\n[discussions]: https://github.com/elgopher/pi/discussions\n[ebitengine]: https://ebiten.org/\n[ebitengine-audio]: https://ebitengine.org/en/examples/#Audio\n[go-downloads]: https://go.dev/dl/\n[issues]: https://github.com/elgopher/pi/issues\n[mod]: https://en.wikipedia.org/wiki/Module_file\n[pico-8]: https://www.lexaloffle.com/pico-8.php\n[pico-8-faq]: https://www.lexaloffle.com/pico-8.php?page=faq\n[picotron-faq]: https://www.lexaloffle.com/picotron.php?page=faq\n[piweb]: https://github.com/elgopher/piweb\n[pi-codecov]: https://codecov.io/gh/elgopher/pi\n[pi-godoc]: https://pkg.go.dev/github.com/elgopher/pi\n[pi-template]: https://github.com/elgopher/pi-template\n[quasilyte-gdata]: https://github.com/quasilyte/gdata\n[quasilyte-xm]: https://github.com/quasilyte/xm\n[repostatus-active]: https://www.repostatus.org/#active\n[tiled]: https://www.mapeditor.org/\n[xm]: https://en.wikipedia.org/wiki/XM_(file_format)","funding_links":[],"categories":["Game Development","游戏开发"],"sub_categories":["Search and Analytic Databases","检索及分析资料库"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felgopher%2Fpi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felgopher%2Fpi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felgopher%2Fpi/lists"}