kit

package module
v2.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2026 License: MIT Imports: 3 Imported by: 0

README

kit — the shellcade game developer kit

Write multiplayer terminal games for shellcade.com — develop and test locally with zero setup, compile to WebAssembly, submit the artifact. This module is the complete contract: the wire package and ABI.md define the ABI, and no shellcade-private code is needed (or referenced) anywhere here.

Start with GUIDE.md — or go straight to playing: grab shellcade-kit from this repo's Releases (the one author tool: scaffold, verify, and play artifacts), then:

shellcade-kit new mygame
cd mygame && go mod tidy && go run .

Layout

Path What
kit (root) the authoring surface: Game/Handler/Room, frames, controls
keyhold/, kittest/ held-keys helper for action games; in-memory test double
wire/ the ABI as code: version, names, packed payload codecs
rust/ the Rust guest SDK (shellcade-kit new --rust)
crossverify/ golden vectors binding the Rust delta encoder byte-identical to Go's
ABI.md / GUIDE.md the normative contract / the authoring guide

For complete, published example games, see the games catalog — every game there is conformance-green; pokies exercises every SDK feature.

Write a game

Implement kit.Game + kit.Handler (six callbacks: OnStart/OnJoin/ OnLeave/OnInput/OnWake/OnClose), call kit.Run(game) and add the eight //go:export trampolines. The fastest start is shellcade-kit new mygame, which scaffolds exactly this; for a full real-game reference see pokies in the catalog.

Rules of the road:

  • Frames are pointers (*kit.Frame). A frame is ~46KB; by-value frames explode TinyGo compile time (3s → 3min) and artifact size (600KB → 9MB).
  • Time comes from r.Now() (CallContext time) and code runs only when the host calls you — built-in timers/goroutines never fire. Drive animations and deadlines from OnWake (the host heartbeat).
  • Per-player durable state via r.Services().Accounts.For(p).Store() — the kv keys are namespaced to your game and the player by the host.

The dev loop (three gears)

  1. Inner loop — no wasm at all (~0.1s): go run . in your game directory plays the game natively in your terminal via kit.Main — normal Go builds, delve, prints, real stack traces. Flags: -seed N -heartbeat 50ms -config k=v -handle name.

  2. Artifact check (~4s): build the real wasm and verify it:

    tinygo build -opt=1 -no-debug -gc=leaking -o game.wasm \
        -target wasip1 -buildmode=c-shared .
    
  3. Release: -opt=2 in CI (minutes — never in your inner loop).

  • -opt=1 skips binaryen/wasm-opt (the slow part). Release builds can use -opt=2; expect minutes, run it in CI not your inner loop.
  • -opt=0 is NOT supported (giant unoptimized functions crash wazero's arm64 compiler).
  • -gc=leaking is required for now: TinyGo 0.41's conservative GC faults in this reactor configuration (recorded finding; kit keeps the steady state allocation-free so the leak rate is negligible for play sessions).

Test and play

shellcade-kit check game.wasm     # ABI handshake, meta, scripted room
shellcade-kit play  game.wasm     # play it in this terminal (Esc to leave)
# flags: --seed N --heartbeat 50ms --config key=value --seats N

Multiplayer testing is hot-seat — no SSH, no network. Pass --seats N (or -seats N to go run .) to join N players to the one room; your keyboard drives the active seat and Ctrl-T switches seats, so you can play both sides of a duel from one terminal. The wasm runner renders each seat's own per-player frame, so seat-switching also verifies per-viewer composition.

To play a real published game's artifact, clone the games catalog, build a game's wasm with the dev-profile tinygo build above, and shellcade-kit play game.wasm.

Documentation

Overview

Package kit is the shellcade game developer kit: the authoring surface for wasm games targeting the shellcade ABI (see ABI.md; the wire package is the ABI's code form).

A game implements Game + Handler and calls Main(game) from main(), plus the eight //go:export trampolines for the wasm build — run `gamekit new` for a working scaffold, and see GUIDE.md for the full authoring guide.

This package is a curated facade over internal/game; the implementation is internal so the public surface stays deliberate and versionable.

Index

Constants

View Source
const (
	KindGuest  = game.KindGuest
	KindMember = game.KindMember

	InputRune = game.InputRune
	InputKey  = game.InputKey

	KeyNone      = game.KeyNone
	KeyEnter     = game.KeyEnter
	KeyBackspace = game.KeyBackspace
	KeyEsc       = game.KeyEsc
	KeyTab       = game.KeyTab
	KeyUp        = game.KeyUp
	KeyDown      = game.KeyDown
	KeyLeft      = game.KeyLeft
	KeyRight     = game.KeyRight
	KeyCtrlC     = game.KeyCtrlC

	CtxNav     = game.CtxNav
	CtxCommand = game.CtxCommand
	CtxText    = game.CtxText

	ActNone    = game.ActNone
	ActUp      = game.ActUp
	ActDown    = game.ActDown
	ActLeft    = game.ActLeft
	ActRight   = game.ActRight
	ActConfirm = game.ActConfirm
	ActBack    = game.ActBack
)
View Source
const (
	ModeQuick   = game.ModeQuick
	ModePrivate = game.ModePrivate
	ModeSolo    = game.ModeSolo

	MergeKeepWinner = game.MergeKeepWinner
	MergeKeepLoser  = game.MergeKeepLoser
	MergeSum        = game.MergeSum
	MergeMax        = game.MergeMax

	HigherBetter = game.HigherBetter
	LowerBetter  = game.LowerBetter

	CtxFeatRosterEpoch = game.CtxFeatRosterEpoch

	LifecycleResumable = game.LifecycleResumable
	LifecycleEphemeral = game.LifecycleEphemeral
	LifecycleResident  = game.LifecycleResident

	ConfigText   = game.ConfigText
	ConfigNumber = game.ConfigNumber
	ConfigBool   = game.ConfigBool
	ConfigJSON   = game.ConfigJSON
	BestResult   = game.BestResult
	SumResults   = game.SumResults
	Integer      = game.Integer
	Decimal      = game.Decimal
	Duration     = game.Duration

	StatusFinished = game.StatusFinished
	StatusDNF      = game.StatusDNF
	StatusFlagged  = game.StatusFlagged
)
View Source
const (
	Rows = game.Rows
	Cols = game.Cols

	AttrBold      = game.AttrBold
	AttrDim       = game.AttrDim
	AttrUnderline = game.AttrUnderline
	AttrReverse   = game.AttrReverse
)
View Source
const ABIVersion = game.ABIVersion

ABIVersion is the ABI major version this SDK targets.

Variables

View Source
var (
	White   = game.White
	Red     = game.Red
	Green   = game.Green
	Yellow  = game.Yellow
	Cyan    = game.Cyan
	DimGray = game.DimGray
)

Standard palette.

Functions

func Main

func Main(g Game)

Main, built natively, runs the instant inner-loop dev runner: `go run .` plays the game in this terminal with normal Go tooling and zero wasm. Flags: -seed N · -heartbeat 50ms · -config k=v · -seats N · -handle name.

With -smoke <file> [-smoke-out <dir>] it instead runs the smoke script non-interactively and writes the named shot files — see the smoke package and GUIDE.md "Smoke scripts".

Types

type Account

type Account = game.Account

type AccountStore

type AccountStore = game.AccountStore

type Action

type Action = game.Action

func Resolve

func Resolve(in Input, ctx InputContext) Action

Resolve maps an Input to a semantic Action for the given context — the platform's canonical control vocabulary, reimplemented locally.

type Aggregation

type Aggregation = game.Aggregation

type Attr

type Attr = game.Attr

type Base

type Base = game.Base

type Cell

type Cell = game.Cell

type Color

type Color = game.Color

func Gray

func Gray(v uint8) Color

func RGB

func RGB(r, g, b uint8) Color

RGB constructs a truecolor value; Gray an even gray.

type ConfigKeySpec

type ConfigKeySpec = game.ConfigKeySpec

type ConfigStore

type ConfigStore = game.ConfigStore

type ConfigType

type ConfigType = game.ConfigType

type Direction

type Direction = game.Direction

type Frame

type Frame = game.Frame

func NewFrame

func NewFrame() *Frame

NewFrame returns a blank 24x80 frame. Frames are handled by POINTER throughout the SDK (see ABI.md §6).

type Game

type Game = game.Game

type GameMeta

type GameMeta = game.GameMeta

type Handler

type Handler = game.Handler

type Input

type Input = game.Input

type InputContext

type InputContext = game.InputContext

type InputKind

type InputKind = game.InputKind

type KVStore

type KVStore = game.KVStore

type Key

type Key = game.Key

type Kind

type Kind = game.Kind

type LeaderboardSpec

type LeaderboardSpec = game.LeaderboardSpec

type Lifecycle

type Lifecycle = game.Lifecycle

type MergeRule

type MergeRule = game.MergeRule

type MetricFormat

type MetricFormat = game.MetricFormat

type Mode

type Mode = game.Mode

type Player

type Player = game.Player

type PlayerResult

type PlayerResult = game.PlayerResult

type Result

type Result = game.Result

type Room

type Room = game.Room

type RoomConfig

type RoomConfig = game.RoomConfig

type Services

type Services = game.Services

type Status

type Status = game.Status

type Style

type Style = game.Style

Directories

Path Synopsis
Package docs embeds the author-facing getting-started guide so the shellcade arcade can render it directly in its "Add your own game" screen — a glamour-rendered Markdown pane inside an 80x24 SSH TUI.
Package docs embeds the author-facing getting-started guide so the shellcade arcade can render it directly in its "Add your own game" screen — a glamour-rendered Markdown pane inside an 80x24 SSH TUI.
internal
diffbench
Package diffbench measures candidate frame-delta wire encodings for the shellcade guest->host frame channel against the current full-frame baseline.
Package diffbench measures candidate frame-delta wire encodings for the shellcade guest->host frame channel against the current full-frame baseline.
game
Package kit is the shellcade guest SDK: the authoring surface for wasm games targeting shellcade ABI v2.
Package kit is the shellcade guest SDK: the authoring surface for wasm games targeting shellcade ABI v2.
smoke
Package smoke is the engine behind the public smoke package and the dev runner's -smoke mode: it parses a game's smoke.yaml, executes the script deterministically against a native game (virtual clock, seeded RNG), and renders the named shots.
Package smoke is the engine behind the public smoke package and the dev runner's -smoke mode: it parses a game's smoke.yaml, executes the script deterministically against a native game (virtual clock, seeded RNG), and renders the named shots.
Package keyhold derives "key held" state from terminal auto-repeat — the closest a terminal game can get to press/release semantics.
Package keyhold derives "key held" state from terminal auto-repeat — the closest a terminal game can get to press/release semantics.
Package kittest is an in-memory test double for the kit authoring surface: a Room (plus Services/KV/config) you can drive from plain Go tests, with the sends, posts, and settle recorded for assertions.
Package kittest is an in-memory test double for the kit authoring surface: a Room (plus Services/KV/config) you can drive from plain Go tests, with the sends, posts, and settle recorded for assertions.
Package smoke runs a game's smoke.yaml: a small deterministic script (seed, seats, steps) that drives the game on a virtual clock and dumps named 80×24 screens.
Package smoke runs a game's smoke.yaml: a small deterministic script (seed, seats, steps) that drives the game on a virtual clock and dumps named 80×24 screens.
Package wire IS the shellcade game ABI as code: the version handshake, the export and host-function names, and the packed little-endian payload encodings, expressed over neutral types with zero dependencies.
Package wire IS the shellcade game ABI as code: the version handshake, the export and host-function names, and the packed little-endian payload encodings, expressed over neutral types with zero dependencies.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL