A PICO-8-inspired fantasy console with a web-based editor. Games are written in JavaScript with a simple, constrained API.
- 128x128 pixel display with 16-color PICO-8 palette
- 256 sprites (8x8), 128x64 tile map, 64 SFX slots with 4 channels
- Multi-file code editor with CodeMirror, autocomplete, and vim mode
- Visual sprite editor, map editor, and sound editor
- Cloud save, cart library, forking, and thumbnail capture
- 60fps game loop with
_init(),_update(),_draw()lifecycle - Sandboxed iframe execution for security
| Resource | Limit |
|---|---|
| Screen | 128x128 pixels |
| Colors | 16 (PICO-8 palette) |
| Sprites | 256 (8x8 each) |
| Map | 128x64 tiles |
| SFX | 64 slots, 4 channels |
| Code files | 8 per cart |
| Code tokens | 9,999 per cart |
Carts that exceed the 9,999 token limit cannot be saved to the cloud but will still autosave locally.
npm install
npm run dev:editor # Start the editor at http://localhost:3000Or run the standalone console (no editor):
npm run dev # Start at http://localhost:5173- API Reference - Complete function reference
- Getting Started - Tutorial for beginners
- Examples - Code patterns and snippets
- Sound Editor Guide - Creating sound effects
- Editor Guide - Using the web editor
- Cart Format - Cartridge file specification
- Embedding Guide - Embedding the console in your app
fantasy-console-0/
├── packages/
│ ├── console/ # Sandboxed console runtime
│ │ ├── src/
│ │ │ ├── runtime.ts # Game loop and iframe runtime
│ │ │ ├── host.ts # ConsoleHost (parent-side controller)
│ │ │ ├── screen.ts # Screen buffer, camera, clipping
│ │ │ ├── drawing.ts # Drawing primitives (print, printXL, shapes)
│ │ │ ├── input.ts # 8-button keyboard input
│ │ │ ├── sprites.ts # Sprite sheet and rendering
│ │ │ ├── map.ts # Tilemap storage and rendering
│ │ │ ├── palette.ts # 16-color palette system
│ │ │ ├── math.ts # Math API (sin, cos, atan2, etc.)
│ │ │ ├── random.ts # Seeded random number generator
│ │ │ ├── utils.ts # String and array utilities
│ │ │ └── audio/ # Audio engine and SFX codec
│ │ └── docs/ # API docs, examples, guides
│ ├── editor/ # Web-based IDE
│ │ └── src/
│ │ ├── components/ # React components (CodeEditor, SpriteEditor,
│ │ │ # MapEditor, SoundEditor, CartLibrary, etc.)
│ │ ├── context/ # Auth, Cart, Console, Toast contexts
│ │ ├── hooks/ # Keyboard shortcuts, editor history
│ │ ├── services/ # Cart service, likes, thumbnails, cache
│ │ └── lib/ # Supabase client
│ └── types/ # Shared TypeScript definitions
│ └── src/
│ ├── index.ts # Cart, message, and API types
│ ├── sfx.ts # SFX types and constants
│ └── loopGuard.ts # Infinite loop protection
├── docs/ # Project-level documentation
└── package.json # Monorepo root with workspaces
| Function | Description |
|---|---|
cls(col?) |
Clear screen |
pset(x, y, col?) |
Set pixel |
pget(x, y) |
Get pixel color |
rect(x, y, w, h, col?) |
Rectangle outline |
rectfill(x, y, w, h, col?) |
Filled rectangle |
circ(cx, cy, r, col?) |
Circle outline |
circfill(cx, cy, r, col?) |
Filled circle |
oval(x, y, w, h, col?) |
Oval outline |
ovalfill(x, y, w, h, col?) |
Filled oval |
line(x0, y0, x1, y1, col?) |
Draw line |
print(str, x?, y?, col?) |
Print text (3x5 font) |
printXL(str, x?, y?, col?) |
Print text (4x6 font) |
color(col) |
Set default drawing color |
spr(n, x, y, w?, h?, flipX?, flipY?) |
Draw sprite |
sspr(sx, sy, sw, sh, dx, dy, dw?, dh?, flipX?, flipY?) |
Draw sprite sheet region |
pal(c0?, c1?, p?) |
Palette color mapping |
palt(col?, t?) |
Color transparency |
map(celX, celY, sx, sy, celW, celH, layer?) |
Draw map region |
mget(x, y) |
Get map tile |
mset(x, y, val) |
Set map tile |
camera(x?, y?) |
Set camera offset |
clip(x?, y?, w?, h?) |
Set clipping region |
btn(id) |
Button held down |
btnp(id) |
Button just pressed |
sfx(n, channel?, offset?) |
Play/stop sound effect |
abs(x), sgn(x), min(x,y), max(x,y), mid(x,y,z) |
Basic math |
flr(x), ceil(x), sqrt(x) |
Rounding and roots |
sin(x), cos(x), atan2(dx, dy) |
Trig (0-1 angles) |
rnd(x?), srand(seed) |
Random numbers |
sub(str, pos, len?), chr(val), ord(str, pos?) |
String utilities |
add(arr, val, i?), del(arr, val), count(arr), all(arr), foreach(arr, fn) |
Array utilities |
printh(str) |
Debug output |
See the API Reference for full details and examples.
| Index | Color | Hex |
|---|---|---|
| 0 | Black | #000000 |
| 1 | Dark Blue | #1D2B53 |
| 2 | Dark Purple | #7E2553 |
| 3 | Dark Green | #008751 |
| 4 | Brown | #AB5236 |
| 5 | Dark Gray | #5F574F |
| 6 | Light Gray | #C2C3C7 |
| 7 | White | #FFF1E8 |
| 8 | Red | #FF004D |
| 9 | Orange | #FFA300 |
| 10 | Yellow | #FFEC27 |
| 11 | Green | #00E436 |
| 12 | Blue | #29ADFF |
| 13 | Lavender | #83769C |
| 14 | Pink | #FF77A8 |
| 15 | Light Peach | #FFCCAA |
function _init() {
// Called once at start
}
function _update() {
// Called at 60fps - update game state
}
function _draw() {
// Called at 60fps after _update - draw graphics
}| Button | ID | Keys |
|---|---|---|
| LEFT | 0 | Arrow Left, A |
| RIGHT | 1 | Arrow Right, D |
| UP | 2 | Arrow Up, W |
| DOWN | 3 | Arrow Down, S |
| B | 4 | Z, J |
| A | 5 | X, K |
| START | 6 | Enter, Space |
| SELECT | 7 | Shift (left or right) |
Build all packages:
npm run buildRun the editor in development mode:
npm run dev:editorRun the standalone console in development mode:
npm run devMIT