Sample Scene

The SDK ships a working sample under the bundled sample/ project that demonstrates real-time Contact detection and rendering. This page focuses on the Touch Canvas and ends with pointers to the other domains the sample also exercises.

For a clean scaffolding path, see the bundled bootstrap skill for greenfield Board Godot projects.

What It Demonstrates

  • Real-time detection and tracking of Pieces and finger Contacts.
  • A live model picker that swaps the active Piece Set at runtime.
  • Visual feedback for glyph_id, orientation, and finger vs Piece classification.
  • A sidebar that exercises every other SDK domain (session, save, avatar, pause, application).

Running the Sample

Open sample/project.godot in Godot and install the Custom Android Build Template once via Project > Install Android Build Template. The first time you do this, add noCompress "pck", "sparsepck" to the aaptOptions block in android/build/build.gradle, right after the ignoreAssetsPattern line — Godot’s stock template doesn’t set this, and without it the PCK is deflated inside the APK and cold boot takes ~2 minutes instead of a few seconds.

Then export the APK with Godot’s own Android export — no separate build step or script:

  • Editor: Project > Export Project… > Android.
  • Headless: godot --headless --export-debug "Android" sample.apk.

The Android export preset has gradle_build/use_gradle_build enabled, so the export runs the Gradle build, bundles the addon’s board.aar (so libboard.so is present for the install gate) and the Piece Set Model into the PCK, and signs with the debug keystore. The model loads from the PCK, so a vanilla export Just Works — no asset staging.

To install, open the Board Connect web UI in a browser (the Board shows its address under Settings > System) and drag sample.apk onto it, then launch the sample from the Library. The right side is a full-height sidebar; the rest of the screen is the touch canvas.

Agent install: Use the board-connect CLI (the agent-facing Board Connect client, installable from dev.board.fun/connect/install — no ADB, no scripts). Run board-connect pair <host> once (tap Approve on the device); that saves the Board as the default, so later commands need no address. Then board-connect install sample.apk --launch (or board-connect install sample.apk then board-connect launch <package>).

Touch Canvas Walkthrough

The canvas lives at sample/touch_canvas.gd. It subscribes to Board.input.contacts_received and re-draws on every inference frame:

extends Node2D

func _ready() -> void:
    if not Engine.has_singleton("BoardSDK"):
        return
    Board.input.contacts_received.connect(_on_contacts)
    Board.input.subscribe()

func _on_contacts(contacts: Array) -> void:
    _contacts = contacts
    queue_redraw()

func _draw() -> void:
    for c in _contacts:
        var pos := Vector2(float(c.x), float(c.y))
        if int(c.glyph_id) > 0:
            draw_circle(pos, 28.0, Color(1.0, 0.42, 0.61, 0.85))
            var rad := deg_to_rad(float(c.orientation))
            draw_line(pos, pos + Vector2(cos(rad), sin(rad)) * 28.0,
                Color.WHITE, 3.0)
        else:
            draw_circle(pos, 20.0, Color(0.0, 0.825, 1.0, 0.85))

Patterns worth copying:

  • Differentiate by glyph_idglyph_id == 0 means finger, 1+ means a Piece type. To follow a single Piece instance across frames, track it by contact_id instead, since two identical Pieces share a glyph_id.
  • Coordinates are display-pixel, Y-down, no rotationc.x / c.y map directly to screen pixels.
  • orientation is degrees, screen-CW positive.

Live Model Picker

The sidebar’s Touch section is a live model browser. On startup it fetches the manifest at https://dev.board.fun/downloads/models/manifest.json and lists every available Piece Set. Entries bundled into the export are selectable — picking one calls Board.input.activate("models/<filename>") and the canvas immediately starts recognizing that Piece Set’s Glyphs.

Note: Runtime download isn’t supported — the native plugin reads models from the read-only PCK packaged inside the APK. To add a Piece Set, drop its .tflite under the project’s assets/models/ directory (the SDK loads from res://assets/ plus the model path) so the export bundles it into the PCK, then re-export and reinstall.

Debug Overlay UI

The Godot SDK has no in-editor debug overlay; the equivalent is the diagnostic log stream. The sample logs every meaningful event (Contact begin/end, session changes, save CRUD, pause-context push) via print(), so the app’s logs over Board Connect are your debug overlay. Pull them with board-connect logs <package>, then filter by SDK module:

board-connect logs fun.board.smoketest
# Each line is tagged with its originating domain, e.g.:
[Board.input]   contact begin id=3 glyph_id=1
[Board.session] player joined slot=2

Add --follow to stream the logs live until Ctrl-C while you reproduce a bug: board-connect logs fun.board.smoketest --follow.

Each line is tagged with the originating domain so you can grep for [Board.input], [Board.session], and so on. Java-side Log.d(...) lines from the AAR show up in the same stream.

Testing with Hardware

Once the sample launches, verify:

  • Plugin loaded — Sidebar Status shows on_device: true.
  • Touch input live — Drag a finger across the canvas; a blue disc tracks it.
  • Piece detection — Place a Piece from the active Piece Set; a pink disc with orientation tick and glyph_id appears.
  • Pause overlay — Tap “Set context” in the sidebar, tap the system menu button (top-right, shown automatically by the OS), tap Resume; the result label updates.
  • Logs clean — the board-connect logs stream shows no SCRIPT ERROR or FATAL.

Adapting to Your Game

The sample is intentionally comprehensive. A typical starting point:

  1. Keep Board.initialize(APP_ID) and the input subscription pattern from touch_canvas.gd.
  2. Replace the _draw body with your game’s per-Contact rendering or state machine.
  3. Wire Board.session, Board.save, and Board.pause only when you need players, persistence, or the pause overlay.

Other Domains in the Sidebar

The sample’s right sidebar also exercises every other SDK domain:

  • Session — Player list, OS Player selector, AI player registration, Profile switcher. See Player Management and Profile Switcher.
  • Saves — Save game CRUD with cover images and metadata. See Save Games.
  • AvatarBoard.avatar.await_load_avatar(int(player.avatar_id)) returns a cached, ready-to-display ImageTexture for a known player’s avatar.
  • Pause — Interactive editor for the pause-overlay context. See Pause Menu.
  • ApplicationBoard.application.quit() (always preferred over get_tree().quit() on-device).

Next Steps