# 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](https://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_id`** — `glyph_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 rotation** — `c.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](https://docs.dev.board.fun/guides/player-management) and [Profile Switcher](https://docs.dev.board.fun/guides/profile-switcher).
- **Saves** — Save game CRUD with cover images and metadata. See [Save Games](https://docs.dev.board.fun/guides/save-games).
- **Avatar** — `Board.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](https://docs.dev.board.fun/guides/pause-menu).
- **Application** — `Board.application.quit()` (always preferred over `get_tree().quit()` on-device).

## Next Steps

- [Quick Start](https://docs.dev.board.fun/godot/getting-started/quick-start) — fastest scaffolding path
- [Setup Reference](https://docs.dev.board.fun/godot/getting-started/setup-reference) — full project configuration
- [Deploy](https://docs.dev.board.fun/godot/getting-started/deploy) — export, install, and run on a Board
- [Touch System](https://docs.dev.board.fun/learn/touch-system) — what the sensor sees
