Game module format
A native game is a WebAssembly module that exports its linear memory as memory along with the functions detailed below. All parameters and return values are 32-bit integers, and all pointers are byte offsets into linear memory. The Rust and C SDKs implement this interface automatically; use this reference when inspecting the ABI or targeting it from another language.
Required exports
| Export | What it does |
|---|---|
wg_init(seed: u32) | Starts a new run seeded with a random 32-bit integer. |
wg_frame(buttons: u32, dt_ms: i32) -> u32 | Advances the simulation by dt_ms milliseconds with the given button bitmask held, renders the frame, and returns event flags. When dt_ms is 0, renders the current state without advancing the simulation. |
wg_fb() -> ptr | Returns the byte offset of the RGBA framebuffer in linear memory. |
wg_w() -> i32, wg_h() -> i32 | Returns the framebuffer width and height in pixels. |
wg_score() -> i32 | Returns the player's current score. |
wg_state() -> ptr, wg_state_size() -> i32 | Returns the address and byte length of the serialized game state buffer. |
wg_state_loaded() -> i32 | Called after the host copies a saved state into the wg_state() buffer; return 1 to accept the state or 0 to reject it. |
Frames
After calling wg_init, the host page invokes wg_frame once per display refresh with the elapsed time in milliseconds since the previous frame (clamped to at most 100 ms) and the current button bitmask. Brief taps pressed and released between refreshes are latched so they still register on the next frame. The loop pauses automatically while a host overlay is open or the browser tab is hidden; when the host needs to redraw the canvas without advancing gameplay (such as after resizing the viewport or restoring a save state), it calls wg_frame with dt_ms = 0.
Buttons
Controller inputs are passed as a bitmask combining keyboard bindings, on-screen touch controls, and connected gamepads:
| Bit | Button | Keys |
|---|---|---|
| 1 | Up | Arrow Up, W |
| 2 | Down | Arrow Down, S |
| 4 | Left | Arrow Left, A |
| 8 | Right | Arrow Right, D |
| 16 | A | Space, Z |
| 32 | B | X, U, Backspace |
| 64 | Start | Enter, P |
Events and sound
The bitmask returned by wg_frame signals gameplay events to the host page, which synthesizes a matching sound effect for each flag:
| Bit | Event | When |
|---|---|---|
| 1 | Blip | Minor movement or UI step |
| 2 | Hit | Item collected or point scored |
| 4 | Lose | Life or attempt lost |
| 8 | Game over | Run ended; the host page reads wg_score() |
| 16 | Level | Stage or level cleared |
| 32 | Win | Combined with Game over: the run was won |
The picture
The framebuffer consists of wg_w() * wg_h() 4-byte pixels in RGBA byte order (0xAABBGGRR as a 32-bit little-endian word, with alpha set to 255). By default, the host scales the framebuffer to fit the stage while preserving its aspect ratio; modules that export wg_resize receive the stage's exact device-pixel dimensions instead so they can render crisply at any resolution.
Saves
All persistent state for a run must reside within the contiguous memory block returned by wg_state. The host copies those bytes directly for Resume snapshots, manual save slots, and cloud saves, and writes them back into memory when restoring. Before restoring, the host verifies that the byte length matches wg_state_size() and then calls wg_state_loaded—store a version tag inside your state struct and return 0 if any fields are out of range so outdated or corrupted saves are safely rejected.
Optional exports
The host page invokes these hooks automatically whenever a module exports them.
| Export | What it does |
|---|---|
wg_resize(w, h) | Resizes the framebuffer to w × h device pixels (up to ~2.4 million pixels); the host re-queries wg_w() and wg_h() afterward. |
wg_dpr(d) | Passes the device pixel ratio multiplied by 100 prior to wg_resize(), for games that scale UI elements in CSS pixels. |
wg_drawn() -> i32 | Returns 1 if the most recent wg_frame() modified the framebuffer; when omitted, the host uploads the framebuffer every frame. |
wg_mouse(x, y, buttons) | Passes pointer coordinates in framebuffer pixels and active button bits (1 = left, 2 = right, 4 = middle, 8 = touch), or (-1, -1) when the pointer leaves the canvas. |
wg_pointer(x) | Simplified horizontal pointer input for paddle games (x in framebuffer pixels, or -1 when outside the canvas). |
wg_wheel(d) | Passes vertical scroll wheel delta in hundredths of a line (positive values scroll down). |
wg_pinch(x, y, d) | Passes two-finger pinch midpoint and finger distance in framebuffer pixels (d = 0 when lifted). |
wg_key(code) -> i32 | Passes direct keyboard input: lowercase ASCII code, physical digit row (or + 0x100 with Shift held), 8 (Backspace), 127 (Delete), 13 (Enter), or 0xF700–0xF703 (arrow keys). Return 1 if consumed, or 0 to let the key fall through to standard button mapping. |
wg_lang(code) -> i32 | Passes the active page language before wg_init() as a two-byte little-endian ASCII code ("zt" for Traditional Chinese). The return value is ignored. |
Page menus
Modules that export wg_option delegate their start, pause, and game-over screens to the host page. Because option names, post-game stat labels, and level-select metadata are defined in the site catalog, the standalone test player displays the generic host overlays without custom option selectors or stat rows.
| Export | What it does |
|---|---|
wg_option(i, v) -> i32 | Sets option i to choice index v for the next wg_init() call (pass v < 0 to query the current value). Exporting this function delegates start, pause, and game-over overlays to the host page and routes the Start key to the host pause menu. |
wg_over() -> i32 | Returns 1 once the current run has ended in victory or defeat. |
wg_won() -> i32 | Returns 1 if the completed run ended in victory. |
wg_stat(i) -> i32 | Returns post-game statistic i for display on the game-over overlay (return -1 to hide that row). |
wg_best(v) -> i32 | Receives the player's personal best score from the host page for games that render their own high-score display. |
wg_reached(), wg_cleared(), wg_level_score() | Reports level progression for level-select menus: highest reached level, most recently cleared level, and the score earned on that level. |
Screen-reader board accessibility hooks (wg_a11y_*) are documented in wg.h, and two-player online room hooks (wg_net_*) are documented in flipside.c.
Imports
A module may optionally import a single host function, env.wg_panic(msg: ptr, len: i32), which halts execution and displays the UTF-8 error message alongside the WebAssembly call stack on the crash screen. Modules that declare any other imports are rejected at load time, ensuring games remain sandboxed from the DOM, network, and local filesystem.