A minimal starting point for PICO-8
carts in the Zed editor. Zed has no PICO-8 extension (a
pico8-ls port exists but is
unpublished and dev-install only), so this starter takes the route the PICO-8
community already recommends for external editors: the cart is a thin shell,
and the code lives in src/*.lua, pulled in with #include. That lets the
plain Lua extension do all the work — autocomplete, hover docs,
format-on-save, one-key run.
Clone it, run it, and start replacing the moving square with your game.
- 🎮 PICO-8 API autocomplete & hover docs via
.luarc.json— the full API is vendored as LuaCATS stubs inpico8-api/(MIT, from ahai64/pico8), with Lua's standard libraries switched off so completions only offer what the console actually has. Typos in API calls get flagged as undefined globals. - 🎑 Format on save with StyLua
(single-line
ifkept single-line — it's PICO-8) - ⬅️ Glyph snippets — all 26 PICO-8 icon characters as
p8-prefixed Zed snippets (p8x→ ❎), one copy-command to install - ⚡ Zed tasks to run the cart and to open it in PICO-8's own editors
- 🧱 Minimal structure: a shell cart + one
src/main.lua(a moving square)
- Zed with the Lua extension (
zed: extensions) - PICO-8 (it's paid software) —
pico8on yourPATH - StyLua —
cargo install stylua --features lua52,lua53,lua54,luau,luajit
- Use this template on GitHub (or clone) and open the folder in Zed.
- Run it:
task: spawn→ Run cart, or bind a key:// ~/.config/zed/keymap.json { "bindings": { "ctrl-shift-r": ["task::Spawn", { "task_name": "Run cart" }] } }
- Write code in
src/main.lua. To split it up, add more files undersrc/and one#include src/whatever.lualine per file ingame.p8— all included files share one global scope, so there's norequire(). - Draw sprites, lay maps, make sfx/music with the Open in PICO-8 task —
that data lives in
game.p8itself. Saving inside PICO-8 keeps the#includeline intact (just don't edit the code in there too).
.
├── .zed/ Zed project settings + tasks
├── .luarc.json LuaLS config (PICO-8 API, std libs off, shorthand ops)
├── .stylua.toml Formatting rules
├── pico8-api/ Vendored PICO-8 API stubs (autocomplete/hover/checks)
├── snippets/ Glyph snippets → copy to ~/.config/zed/snippets/
├── game.p8 The cart: one #include line + your sprites/map/sfx
└── src/main.lua The actual code (moving square)
PICO-8's Lua accepts shorthand that vanilla Lua doesn't: x += 1, !=,
? "hi", single-line if (x) .... .luarc.json teaches LuaLS the operators
so they won't get red squiggles — but StyLua can't parse them, so a file
that uses shorthand silently stops being formatted. The starter code sticks
to the vanilla subset (x = x + 1), which PICO-8 runs just as happily; it's
also simply real Lua, so everything you learn transfers.
PICO-8's icon characters are ordinary Unicode in external files — PICO-8
converts them on load (verified: all 26 map to chr(128)–chr(153)). Zed
has built-in snippets, but only reads them from your config directory, so
install the set once:
mkdir -p ~/.config/zed/snippets && cp snippets/lua.json ~/.config/zed/snippets/(Already have a lua.json there? Merge by hand — snippets: open folder.)
Then type p8x → ❎, p8heart → ♥, p8left → ⬅️, and so on. Inside a
string the completion menu may not pop up on its own — trigger it with
editor: show completions (ctrl-space). The prefixes are all p8…, so
they stay out of the way in your other Lua projects.
Two ways to use glyphs, one caveat:
- In strings —
print("press ❎ to jump")— fine everywhere: StyLua formats the file, LuaLS is happy, PICO-8 draws the icon. This is whatsrc/main.luadoes. - Bare, as button constants —
btn(❎)instead ofbtn(5). PICO-8 predefines the six button glyphs as0–5, and LuaLS is set up to understand that (runtime.unicodeNamein.luarc.jsonpluspico8-api/glyphs.lua). But StyLua can't parse them, so — same as the shorthand ops — a file using bare glyphs silently stops being formatted.
printh("x=" .. player.x) prints to the task terminal in Zed when the
cart is launched with the Run task — that's your console.log. On screen,
print() draws text. Press Esc while the cart runs to drop into PICO-8's
console, poke at globals, then resume. info() there shows your token
count (carts max out at 8192 tokens — #included code counts).
- Want the real dialect (shorthand,
?) checked in the editor? Install the pico8-ls Zed extension as a dev extension — it may reach the extension registry eventually. - Token-golfing near the 8192 limit: shrinko8 minifies on export.
- The PICO-8 manual and the BBS — half the fun is reading other people's carts.