---
name: banto-game
description: "Build or edit a multiplayer party game with the Banto DSL — scaffold with the banto CLI, write .banto files, compile, and publish to banto.tv. Use when the user wants to create, extend, or fix a Banto game."
argument-hint: "<game-dir-or-name> [what to build or change]"
license: MIT
---

# Build a Banto game

You are building a **multiplayer party game** with the Banto DSL. One person is
the **host** (a shared screen everyone watches — a TV or laptop) and several are
**players** (each on their own phone). You write declarative `.banto` files that
describe what each viewer sees and what happens when they tap things; the Banto
runtime delivers those views to every screen.

## Reference docs (read these — you don't have the source repo)

All authoritative documentation is hosted. Fetch it as you work; **do not** rely
on memory or invent components/functions:

- **Everything in one file (best for a first pass):** <https://blog.banto.tv/llms-full.txt>
- Getting started: <https://blog.banto.tv/docs/getting-started>
- The language: <https://blog.banto.tv/docs/language-guide>
- CLI reference: <https://blog.banto.tv/docs/cli>
- Recipes (copy-paste patterns): <https://blog.banto.tv/docs/recipes>
- Registry reference (every `cpnt.*` / `func.*` / `client.*` you may call): <https://blog.banto.tv/docs/registry-reference>
- Gotchas (compile errors → fixes): <https://blog.banto.tv/docs/gotchas>

Read **getting-started → registry-reference → recipes → gotchas** before your
first build; pull up the language guide for a specific feature. Only call
components and functions that appear in the registry reference — anything else is
a compile error.

## Setup (once)

The user needs the CLI installed and to be logged in:

```bash
npm install -g @bantohq/cli
banto auth                 # opens a browser to log in to banto.tv
```

Encourage them to also install the **Banto DSL** editor extension (VS Code
Marketplace, or Open VSX for Cursor/Windsurf) — it shows the same type errors you
get from `banto build`, inline as you type.

## How you work

Banto games run on **banto.tv** — that is where they are hosted and played — but
you don't need real phones to test them: `banto sandbox` opens an owner-only
**sandbox** that runs the real game with the host screen and simulated player
windows side by side in one browser. Your loop:

1. **Scaffold** if the game doesn't exist yet: `banto init <dir>` creates an
    "empty lobby" starter (host shows a room code + kick list, players see
    "you're in").
2. **Write** `.banto` files. Keep the [design constraints](#design-constraints)
    below in mind from the start.
3. **Compile often:** `banto build`. Fix every error before moving on (warnings
    are OK). This is your fastest correctness check — the compiler type-checks
    the whole game. Cross-reference errors against the gotchas doc.
4. **Format:** `banto fmt` to normalize the source.
5. **Publish privately to playtest:** set `"public": false` in
    `banto.config.json`, then `banto publish`. The game becomes reachable only by
    the author (and anyone with a direct link). Re-running `banto publish` updates
    the same game in place. **The sandbox opens the *published* build, so publish
    (and re-publish after every change) before testing.**
6. **Test in the sandbox:** `banto sandbox` opens
    `banto.tv/sandbox/<your-game>` — the host screen plus simulated player windows,
    no phones required. `-t / --template <0-3>` picks a layout preset (how many
    player windows to tile; default `2`); **+ Add player** adds/drops players live.
    - **If you can drive a browser yourself** (a Playwright/computer-use/window
      tool): open the URL `banto sandbox` prints and *play the game* — click
      through the host and each player window, walk every phase, and exercise the
      edge cases you'd otherwise ask the user to check. Click the **Inspector**
      button in the **top-right** to open a live panel of all `var.*` and
      state-params, the datasets, each window's `cstate`, and a **Logs** panel of
      your `func.log(...)` output plus any runtime errors — use it to confirm state
      transitions and diagnose bugs. Iterate: edit → `banto build` →
      `banto publish` → reload the sandbox.
    - **If you can't drive a browser:** point the user to run `banto sandbox`
      themselves (it opens in their browser) and report back, or have them host it
      live on banto.tv from a couple of phones/tabs. Tell them exactly which phases
      and edge cases to check.

> The sandbox is **owner-gated**: the browser must be signed in to banto.tv as the
> project's owner (the account from `banto auth`). A fresh automated browser won't
> be logged in — sign it in first, or it can't open the sandbox.

**Debugging tip:** drop `func.log({ message: "...", level: "info" })` into actions
and listeners while developing — the output appears in the sandbox Inspector's
**Logs** panel (and never reaches real players), so it's a clean way to trace
what your server logic is doing. Remove or quiet them before shipping.

Whether or not you can drive the sandbox yourself, lean hard on: compiling
frequently, reading the registry/recipes/gotchas for exact signatures and known
pitfalls, and reading back the `.banto` you wrote to reason through each phase.

## Design constraints (get these right up front)

**Host screen — desktop / TV first, and it MUST NEVER overflow.**
The host view is shown on a big shared screen and must **never scroll in any
direction**. Size fonts, padding, and layout so the *busiest* phase (max players,
longest text, most options on screen at once) still fits within one viewport.
Overflow on the host is a bug. Prefer layouts that scale to content (grids that
wrap, capped font sizes) over anything that can push past the screen edge.

**Player screen — mobile first.**
Each player is on a phone. Design player views for a narrow, tall viewport:
large tap targets, thumb-reachable buttons, one primary action at a time, minimal
text. Player screens may scroll if truly necessary, but a clean phone-sized layout
that doesn't need to is better. Don't assume a mouse or a wide screen.

**Every state needs both fallbacks.**
Each state must include a `host default { condition: true, ... }` **and** a
`plyr default { condition: true, ... }` as the last block of each kind, so
something always renders for both audiences. Put conditional variants above the
default.

## Core language reminders

(The docs are authoritative — this is just orientation.)

- **A project** is a flat folder of `.banto` files: exactly one `globals.banto`,
  exactly one `start.banto` (the entry state), and one file per additional
  **state** (the file name must match its `state` block). Plus `styles.banto.css`
  and `banto.config.json`.
- **State lives on the server.** `var.*` is authoritative server state, mutated
  only inside actions. `cstate.*` is per-player, browser-only draft state (e.g.
  in-progress text) that resets on every state transition. Its `default` is a
  static literal; to seed it from server state on entry (e.g. per-player data),
  add an `init: { cstate.X = … }` block to the `host`/`plyr` view — it runs once
  server-side on state entry/connect and is skipped on incremental updates.
- **Views are declarative.** `host` and `plyr` blocks pick the first block whose
  `condition` is true. No `if`/`for` in views — order blocks for branching, `.map`
  over arrays for lists.
- **`lstn`** listeners fire when their `condition` becomes true — run `actions`
  and/or transition via `next: { state, inputs }`.
- **Components** are `cpnt.X({...})` from the registry, or your own declared in
  `globals.banto`. **Functions** are `func.X` (server-side utilities and game
  control like `func.kickPlayer`) and `client.X` (browser-side, e.g.
  `client.playSound`, only inside action arrows).
- **Actions** are the `() => { ... }` bodies wired to `onClick`/`onChange`/
  `onSubmit`; statements end with `;`. An action must sit **directly** in a
  component's handler slot, or it's silently dropped.
- **Client prelude / epilogue.** A handler splits into `client prelude → server
  body → client epilogue` by source order: `cstate` writes before your first
  `var` write run **instantly in the browser** (no round-trip), the `var`/server
  work runs async, and `cstate` writes after run in the epilogue. Drive
  zero-latency UI (grids, cursors, local toggles) through `cstate` in the prelude
  while the server catches up. Keep client work as a contiguous prefix/suffix and
  never mix a `cstate` and a `var` write in one `if`/`forEach` branch.
- **Datasets** (`data questionSet` / `promptSet` / `dynamic`) are picked by the
  host at game start. Seed one via `new.*` in `banto.config.json` (and bind it
  with `default: { questionSet: "this" }`) or the host sees an empty set.
- **Custom media:** put images/audio in an `assets/` folder, title them in
  `banto.config.json`, run `banto assets push`, and reference them as
  `asst.<name>` in `cpnt.image` / `cpnt.audio` / `client.playSound`.

## Common pitfalls (see the gotchas doc for the full list)

- Binding a text input's `value` straight to a `var` — use a `cstate.<name>`
  draft, write it in `onChange`, commit to `var.*` on `onSubmit`.
- `client.*` calls inside a `.map`/`.forEach` body, or outside an action arrow —
  not allowed.
- Referencing `asst.<name>` for an asset you haven't `banto assets push`ed.
- Custom components and `func` blocks can't read game state — pass everything in
  as `params` / arguments.
- Host overflow (see above) — always the most common visual bug.

## Report back

When you finish a pass, tell the user: what the game does now, that it compiles
(`banto build` clean), and that it's published (privately, if still iterating).
If you drove the sandbox yourself, say what you played through and what you saw in
the Inspector; otherwise point them at `banto sandbox` (or a live host) and list
**exactly what to test** — the phases to walk through and the edge cases you
couldn't verify. Either way, real multi-device play is the final check: some
timing, layout, and phone-input issues only surface on actual phones. Their
playtest feedback drives the next iteration.
