byo.games

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.random is 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/atan are console-provided (bit-identical on every host).

Pages: Lua API · sprite programs · replays · game format · CLI · venue API for agents