A Zorb Game Capsule is a standalone WASM binary that implements the Z-machine logic. It acts as a black box that communicates with a host environment (the "Host") via WASM imports in the zio namespace.
Required Interface
The Host must provide the following functions:
print_char(char: i32)
Outputs a single ZSCII/Unicode character to the user's display.
print_num(num: i32)
Outputs a signed 32-bit integer to the user's display.
read_char() -> i32
Waits for a single character input from the user and returns its ZSCII value.
get_random(max: i32) -> i32
Returns a random integer between 1 and max (inclusive). If max is negative or zero, it may reset the PRNG state.
get_random_seed() -> i32
Returns a 32-bit integer to seed the Z-machine's internal PRNG.
halt(reason: i32, pc: i32, opcode: i32)
Called when the Z-machine encounters a fatal error or a quit instruction.
Reasons include:
0: Normal exit (quit)1: Stack overflow2: Stack underflow3: Illegal opcode4: Static memory violation
sound_effect(number: i32)
Plays a sound effect.
1: High-pitched bleep.2: Low-pitched bleep.3+: Story-defined sound effect ID.
check_interrupt() -> i32
Polled by the WASM capsule to check for Host-triggered save/restore or undo requests. This allows the Host to signal state management operations asynchronously, even while the Z-machine is waiting for input.
0: No request.1: Save.2: Restore.3: Save Undo.4: Restore Undo.
Screen Model Interface (V3-V8)
The following functions are used to implement the Z-machine screen model (Spec 8). If the Host signals support via get_capabilities, it must provide these:
set_window(window_id: i32)
Directs subsequent output and cursor operations to the specified window.
0: Lower window (scrolling).1: Upper window (non-scrolling).
split_window(lines: i32)
Splits the screen so that Window 1 occupies the top lines of the display. If lines is 0, Window 1 is collapsed. In a CLI, this typically reserves the top N lines for a fixed status display.
set_cursor(line: i32, col: i32)
Moves the cursor to the specified coordinates within the currently selected window. Coordinates are 1-indexed.
erase_window(window_id: i32)
Clears the specified window. If window_id is -1, the entire screen is cleared and all windows are reset.
erase_line(value: i32)
Erases from the current cursor position to the end of the line.
set_text_style(style: i32)
Sets the text rendering style. Styles are bit-mapped:
0: Roman (Normal)1: Reverse Video2: Bold4: Italic8: Fixed-pitch
set_colour(foreground: i32, background: i32)
Sets the text colors.
1: Default2: Black3: Red4: Green5: Yellow6: Blue7: Magenta8: Cyan9: White
get_screen_size() -> i32
Returns the current dimensions of the host display as a packed 32-bit integer: [height:16, width:16].
Story Metadata Interface (Orbit Radio)
All Game Capsules provide access to semantic metadata extracted during compilation. This is used by the Host to determine how to present out-of-band features like "Orbit Radio".
zio_get_version() -> i32
Returns the Z-machine version of the story.
zio_get_serial() -> i64
Returns the 6-byte serial number string packed into a 64-bit integer (little-endian).
Reassembly Examples:
Elixir (Wasmex):
{:ok, [serial_i64]} = Wasmex.call_function(instance, "zio_get_serial", []) serial = <<serial_i64::little-64>> |> binary_part(0, 6)JavaScript (Node.js/Browser):
const serialInt = instance.exports.zio_get_serial(); // BigInt const buf = Buffer.alloc(8); buf.writeBigUInt64LE(serialInt); const serial = buf.toString('ascii', 0, 6);
zio_get_command_prefix() -> i32
Returns the ZSCII/Unicode character recommended for out-of-band commands (e.g., / or ~).
zio_get_chat_prefix() -> i64
Returns a null-terminated ASCII/UTF-8 string (up to 8 bytes) representing the recommended chat tag (e.g., RAD, ORB, VOX) packed into a 64-bit integer (little-endian).
zio_get_channel_prefix() -> i64
Returns a null-terminated ASCII/UTF-8 string (up to 8 bytes) representing the recommended user label (e.g., FOLKS, SOULS, MATES) packed into a 64-bit integer (little-endian).
String Reassembly (JavaScript):
function readI64String(bigInt) {
const buf = Buffer.alloc(8);
buf.writeBigUInt64LE(bigInt);
return buf.toString('utf8').replace(/\0/g, '');
}
const chatTag = readI64String(instance.exports.zio_get_chat_prefix());Save/Restore Interface
The following functions are used to implement the Z-machine save and restore instructions.
save(pc: i32, sp: i32, fp: i32, csp: i32, random_state: i32) -> i32
Requests the Host to save the current state.
pc: Current Program Counter.sp: Current Stack Pointer (word count).fp: Current Frame Pointer (word count).csp: Current Call Stack Pointer (word count).random_state: Current PRNG state. Returns1if the save was successful,0otherwise.
restore() -> i32
Requests the Host to restore a previously saved state.
Returns 1 if a state was successfully restored, 0 otherwise.
get_restored_pc() -> i32
Returns the pc from the last successful restore().
get_restored_sp() -> i32
Returns the sp from the last successful restore().
get_restored_fp() -> i32
Returns the fp from the last successful restore().
get_restored_csp() -> i32
Returns the csp from the last successful restore().
get_restored_random_state() -> i32
Returns the random_state from the last successful restore().
Undo Interface
The following functions are used to implement the Z-machine save_undo and restore_undo instructions (V5+).
save_undo(pc: i32, sp: i32, fp: i32, csp: i32, random_state: i32) -> i32
Requests the Host to save the current state for a future undo.
Returns 1 if successful, 0 otherwise, and -1 if not supported.
restore_undo() -> i32
Requests the Host to restore the last state saved via save_undo.
Returns 1 if successful, 0 otherwise.
get_undone_pc() -> i32
Returns the pc from the last successful restore_undo().
get_undone_sp() -> i32
Returns the sp from the last successful restore_undo().
get_undone_fp() -> i32
Returns the fp from the last successful restore_undo().
get_undone_csp() -> i32
Returns the csp from the last successful restore_undo().
get_undone_random_state() -> i32
Returns the random_state from the last successful restore_undo().
Optional Interface (Capabilities)
The Host can signal support for optional features. The Capsule checks these via the following host import:
get_capabilities() -> i32
Returns a bitmask of supported features.
Bit 0 (0x01): Status line available.Bit 1 (0x02): Screen splitting available.Bit 2 (0x04): Variable-width font available.Bit 3 (0x08): Font 3 (Character Graphics) available.Bit 4 (0x10): Color available.Bit 5 (0x20): Timed input available.
Appendix: Internal Memory Layout
The following memory locations are used internally by the Capsule. The Host is not required to access these, but they are documented for transparency and debugging.
0x00000: Story Memory (Header, Dynamic Memory, Static Data, Z-code).0x80000: Unicode Translation Table.0x81000: Alphabet Tables.0x82000: Dictionary Hash Table (O(1) lookups).0x8A000: Orbit Radio Metadata (Serial, Tags, Prefixes).0x90000: Z-stack.0x98000: Call Stack.