Changelog
Notable changes to the Board Godot SDK. The format follows Keep a Changelog, and the project adheres to Semantic Versioning.
Note: The Godot SDK is at v1.0.0-beta.1, the first beta. It covers the full public-API surface of the Board platform and is the first version intended for building games against, ahead of the stable 1.0.0.
[1.0.0-beta.1] — 2026-05-26
First beta release. The SDK covers the full public-API surface of the Board platform across input, session, save, avatar, pause, and application domains, with a no-build-script export-and-install path and a polished sample app.
Added
Board.input.contacts_received— the single per-frame touch signal: a snapshotArrayof contactDictionaryentries, each carryingphase_id(BEGAN/MOVED/ENDED/CANCELED/STATIONARY),is_touched,glyph_id, andcontact_id. Games that want discrete edges (tap-down / tap-up viais_touched, or piece-lifted) keep their own previous-frame map keyed bycontact_idand diff it each frame. This mirrors the Unity SDK’s per-frame snapshot model.- Cached, player-scoped avatar loader on
Board.avatar(mirrors Unity’sBoardPlayer.avatar):await_load_avatar(avatar_id: int) -> ImageTexture— returns a ready-to-display, already-decodedImageTexture, ornullon failure / off-device. Cached after first load; concurrent loads of the same id coalesce onto one fetch. Pass a player’savatar_idfromBoard.session.get_players()(the playerDictionary’savatar_idis aString, so call withint(player.avatar_id)).await_default_avatar() -> ImageTexture— the default avatar (id0).clear_cache() -> void— drop cached textures.
Board.save.get_app_storage_info() -> Dictionary— synchronous storage query. Keys:total_storage(int bytes),used_storage(int bytes),remaining_storage(int bytes),usage_percentage(float0.0–1.0). Off-device returns{}. Use it to render a storage meter or pre-flight whether a save fits. Mirrors Unity’sGetAppStorageInfo.- Optional
ai_type_indicesfilter on the session selector —Board.session.present_add_player(ai_type_indices := PackedInt32Array())andBoard.session.present_replace_player(session_id, ai_type_indices := PackedInt32Array())now take an optional trailingPackedInt32Array. An empty array (the default) offers all AI types registered viaset_ai_player_types(); a non-empty array restricts the selector’s “Add AI” options to that subset. Existing zero-arg /(session_id)-only calls still work. Mirrors Unity’s selector AI-type filter. - Documented
noCompressone-time setup — after installing the Custom Android Build Template, addnoCompress "pck", "sparsepck"toandroid/build/build.gradle’saaptOptionsblock (right after theignoreAssetsPatternline). Godot’s stock template doesn’t set this; without it the PCK is deflated inside the APK and cold boot takes ~2 minutes instead of a few seconds, because the runtime can mmap the PCK instead of decompressing everyFileAccesscall through ZipInputStream. This is now part of the project setup docs rather than a build-script side effect. scripts/prune_import_cache.py— idempotent orphan.godot/imported/cleanup.- Sample boot scene template —
sample/boot/boot_scene.{tscn,gd}— threaded scene-load with progress bar; ready to swap in as the launch scene. - Pause-context restart custom button wired in the sample sidebar: matches on
Board.pause.ACTION_CUSTOM_BUTTON+custom_button_id == "restart"→get_tree().reload_current_scene.call_deferred(). bootstrap-board-godot-gameskill — interactive Claude skill that scaffolds a new Board game with every best practice from this SDK baked in.- Per-domain consumer-facing
CLAUDE.mdataddon/addons/board_sdk/CLAUDE.md— drops into game-sideaddons/so Claude can read it and know how to use the SDK. - Full Godot documentation under
docs/(22 markdown files) mirroringdocs.dev.board.fun’s sectioning (Getting Started, Learn, Guides, Reference, More, FAQ).
Changed
plugin.cfgversion bumped0.1.0→1.0.0-beta.1.Board.session.is_ready()→Board.session.is_session_ready()— names now mirror the underlying plugin method and pair cleanly withare_services_ready(). Breaking for callers of the previous name.- Sample package renamed
fun.board.smoketest→fun.board.godot_example. - Sample display name
Board Smoke Test→Godot Board Example. board_application.gd— dropped the “(later)” lifecycle-hook stub from the file header; lifecycle stays Godot-native viaNOTIFICATION_APPLICATION_*.board_export_plugin.gd— release export with a missing release AAR now emitspush_warning(...)instead of silently shipping the debug AAR.board_avatar.gd/board_pause.gd— clarified docstrings onawait_load_avatar()andpoll_result()so the caching/coalescing behavior and signal/fallback duality are visible.
Removed
Board.services_readysignal — was declared onboard.gdbut never emitted. UseBoard.session.are_services_ready()to query state directly.
Compatibility
- The compiled
board.aarships pre-built with the addon ataddon/addons/board_sdk/android/bin/debug/board.aar. End users don’t build it. - Requires Godot 4.6.x stable. JDK 17 required for Android builds (Godot 4.6 ships Java 17 bytecode).
- Targets Android API 33 (compile/target SDK), minimum 29.
- Single ABI:
arm64-v8a.
Migration Notes
If you’re upgrading from a pre-v1.0 prerelease:
- Rename
is_ready()calls — search-and-replaceBoard.session.is_ready()→Board.session.is_session_ready()across your codebase. - Drop the
Board.services_readysignal handler if you wired one — the signal was never emitted; queryBoard.session.are_services_ready()directly instead. - Replace the addon — re-copy
addon/addons/board_sdkfrom the new SDK release into your project’saddons/directory. The bundledboard.aarupdates with it. - Bump
plugin.cfgin your local copy if you symlinked the addon at a specific version. New version:1.0.0-beta.1. -
Touch is a single per-frame snapshot —
Board.input.contacts_receivedis the only touch signal. If you need discrete edges (tap-down / tap-up viais_touched, or piece-lifted), keep your own previous-frame map keyed bycontact_idand diff each frame:var _prev := {} # contact_id -> is_touched func _on_contacts_received(contacts: Array) -> void: var seen := {} for contact in contacts: var id: int = contact.contact_id seen[id] = true var was_touched: bool = _prev.get(id, false) if contact.is_touched and not was_touched: _on_tap_down(contact) elif was_touched and not contact.is_touched: _on_tap_up(contact) _prev[id] = contact.is_touched for id in _prev.keys(): if not seen.has(id): _on_piece_lifted(id) _prev.erase(id) - Avatars are loaded per-player, not by arbitrary id — replace any raw-bytes loading with
await Board.avatar.await_load_avatar(int(player.avatar_id)), which returns a ready-to-displayImageTexture. Drop your own decode and caching; the loader decodes, caches, and coalesces concurrent loads for you.
Earlier Versions
The 0.x prerelease series isn’t documented here. v1.0.0-beta.1 is the first documented release, intended for building games against ahead of the stable 1.0.0.