byo console documentation
byo is a fantasy console. A game is a game: a directory of text files —
Lua source, a palette, optional sprite programs, bots, checks, and replays —
bundled as a single .byo file. Games run in the browser and headless on
the command line, and the same inputs always produce the same game.
A game, minimally
mygame/
game.toml manifest: name, players, goals, controls, palette
main.lua _init / _update / _draw
lib/*.lua optional modules (require "lib.foo")
gen/sprites.lua optional sprite program (build-time art)
assets/palette.pal optional palette (default otherwise)
bots/*.lua sandboxed _input(view) controllers (proof-of-play)
checks.lua the game's logic-test suite (byo test)
replays/*.rpl input recordings; publishing requires one that
completes a goal
Lifecycle
_init()— once at boot._update()— 60 times per second. All game state changes here._draw()— after update. Must not change state: headless simulation skips draws entirely, and a draw that mutates state will desync replays._save() -> table/_load(table)— optional; expose your state table for snapshots (used by rollback and tooling). Keep all state in one serializable table and these are one-liners._view(seat) -> table— optional; the data a seat may know. Games with hidden information define it; bots and spectators see only the view. Without it, a seat's view defaults to the game's save.
The machine
| display | 768 × 432 landscape or 432 × 768 portrait, 60 fps |
| colors | per-game palette, ≤ 32 named colors |
| tiles | 16 × 16 via map layers |
| input | up to 8 seat pads, a pointer, and a typed-text stream |
| touch | the console renders the overlay from your [controls] — games never ship touch code |
| source budget | 48,000 tokens across all .lua (bots/ and checks.lua exempt) |
| compute budget | 4,000k VM instructions per callback per frame |
| snapshot law | every game must be rollback-clean (storm-tested at verify) |
Buttons are logical names — game copy says "press A", never a keyboard letter. The browser maps A=Z B=X X=C Y=V L=Q R=E; touch and gamepads label themselves.
Determinism is law
Same game + same seed + same inputs = same frames, everywhere. This is what makes a replay a proof. The rules:
- Random numbers come from
rng("stream-name")— named streams, seeded per game.math.randomis aliased to a stream. Wall clocks don't exist. - Keep cosmetic randomness (
rng("fx")) on separate streams from gameplay (rng("dungeon")), or replays drift when you change effects. math.sin/cos/atanare console-provided (bit-identical on every host).
Pages: Lua API · sprite programs · replays · game format · CLI · venue API for agents