kit

package module
v2.14.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 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=conservative -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=conservative is the build profile (since 2026-06-11): leaking GC made every allocation permanent, so long-lived rooms hit the host's 32 MiB cap and trapped (~52 min of play in production). The previously recorded TinyGo-0.41 conservative-GC fault does not reproduce on 0.41.1 (200k-callback soak, flat memory). Keep steady-state paths allocation-free anyway — it minimizes GC pauses inside the callback deadline.

Test and play

shellcade-kit check game.wasm     # ABI handshake, meta, scripted room
shellcade-kit check .             # + lint Go source for wide-glyph width-contract bugs, then build & check
shellcade-kit lint-width .        # that source lint on its own (file/dir paths; no build)
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
	CtxFeatCharacter   = game.CtxFeatCharacter

	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

	OnImprove = game.OnImprove
	OnChange  = game.OnChange

	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 Cadence added in v2.11.0

type Cadence = game.Cadence

type Cell

type Cell = game.Cell

func CharacterCell added in v2.9.0

func CharacterCell(c Character) Cell

CharacterCell returns the one ready-made cell of a member's character tile: the glyph styled with the resolved ink and background. The zero Character (the game's meta does not declare CtxFeatCharacter) yields a blank cell.

type Character added in v2.9.0

type Character = game.Character

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 ControlDecl added in v2.10.0

type ControlDecl = game.ControlDecl

func KeyControl added in v2.10.0

func KeyControl(k Key, label string) ControlDecl

KeyControl declares a named-key extra control for GameMeta.Controls, e.g. KeyControl(KeyBackspace, "UNDO").

func RuneControl added in v2.10.0

func RuneControl(r rune, label string) ControlDecl

RuneControl declares a printable-rune extra control for GameMeta.Controls, e.g. RuneControl('r', "RESIGN").

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 ScoreKeeper added in v2.11.0

type ScoreKeeper = game.ScoreKeeper

ScoreKeeper standardises live/disconnect/periodic leaderboard posting.

func NewScoreKeeper added in v2.11.0

func NewScoreKeeper(c Cadence) *ScoreKeeper

NewScoreKeeper constructs a ScoreKeeper with the given auto-post cadence.

type Services

type Services = game.Services

type Status

type Status = game.Status

type Style

type Style = game.Style

Directories

Path Synopsis
cmd
shellcade-kit command
Command shellcade-kit is the shellcade game developer kit (PROTOTYPE):
Command shellcade-kit is the shellcade game developer kit (PROTOTYPE):
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.
host
blobstore
Package blobstore is the arcade's wasm blob storage: published catalog artifacts (`artifacts/<sha256>.wasm`, immutable, content-addressed) and room state under the `snapshots/` prefix, in two coexisting schemes:
Package blobstore is the arcade's wasm blob storage: published catalog artifacts (`artifacts/<sha256>.wasm`, immutable, content-addressed) and room state under the `snapshots/` prefix, in two coexisting schemes:
canvas
Package canvas owns the fixed 80x24 cell grid that the lobby and every game render into.
Package canvas owns the fixed 80x24 cell grid that the lobby and every game render into.
gameabi
Package gameabi is the host side of the shellcade wasm game ABI: the Extism (wazero) host adapter that makes a .wasm artifact satisfy sdk.Game/sdk.Handler, and the host functions exposing the Room effect/read surface to the guest.
Package gameabi is the host side of the shellcade wasm game ABI: the Extism (wazero) host adapter that makes a .wasm artifact satisfy sdk.Game/sdk.Handler, and the host functions exposing the Room effect/read surface to the guest.
gameabi/conformance
Package conformance runs a scripted scenario against a wasm game through the REAL gameabi adapter (limits ON) and reports per-callback latency, exit codes, frames, and peak linear memory, plus budget verdicts that name the breached limit, the measured value, and the step that breached it.
Package conformance runs a scripted scenario against a wasm game through the REAL gameabi adapter (limits ON) and reports per-callback latency, exit codes, frames, and peak linear memory, plus budget verdicts that name the breached limit, the measured value, and the step that breached it.
memsvc
Package memsvc is a public, in-memory implementation of the host-side sdk.ServicesFactory (and the matching sdk.AccountStore, sdk.KVStore, sdk.ConfigStore, and leaderboard surfaces).
Package memsvc is a public, in-memory implementation of the host-side sdk.ServicesFactory (and the matching sdk.AccountStore, sdk.KVStore, sdk.ConfigStore, and leaderboard surfaces).
render
Package render converts the fixed 80x24 canvas.Grid into the styled, ANSI- encoded strings the bubbletea front door renders.
Package render converts the fixed 80x24 canvas.Grid into the styled, ANSI- encoded strings the bubbletea front door renders.
sdk
Package sdk is the game engine boundary.
Package sdk is the game engine boundary.
session
Package session defines the transport-agnostic Session boundary.
Package session defines the transport-agnostic Session boundary.
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