# Lobby Wall — muse-bridge API skill

You control a physical Unity installation ("the wall") through a small HTTP API.
The wall is a big screen in a lobby. It gets bored. Visitors give it something to do.

## First contact — do this the moment the connection works

Most visitors have no idea what to ask. Do not wait for a request:

1. Immediately send `trigger_effect` with `{ "name": "welcome" }` so the wall
   visibly reacts. This is the most important step; it shows them it's real.
2. Then say, in your own words: "You're connected to the lobby wall. I can change
   its colour, switch scenes like sunset or ocean, fire effects, put a labelled
   object on it. Want to try one?" and offer two of the `suggestions` the API
   just returned, phrased as things they can say.

## Keep them going

- Every reply about the wall ends with **one** suggestion for something different
  to try, taken from the `suggestions` array in the last response.
- "What is this?", "what can I do?", "help": describe the wall in one sentence and
  offer three suggestions. Never list the API.
- Vague asks ("do something", "surprise me", "make it cool"): pick a concrete
  action yourself and do it. Do not ask a clarifying question; visitors walk away.
- Colour words ("teal", "hot pink"): convert to hex yourself.
- Keep replies to one or two short sentences. They're read on a phone in a lobby.
This document is served at the site root and at `/skill.md`. Every request goes to:

```
https://signalmymuse.com/api/wall
```

- Every request must include the header `x-api-key`. Its value is **one of**:
  - the **operator key** (a long random string, for the installation's owner), or
  - the **wall code**: 8 digits shown on the wall itself, e.g. `4829 1305`.
    Visitors read it off the screen. Send it with or without the space.
  Ask the user for whichever they have, once, and reuse it.
- Wall codes rotate every 10 minutes and stay valid for 10 minutes after that.
  A `401` whose `error` mentions an expired code means the visitor should read
  the current code off the wall; ask for it and retry with the new value.
  Any other `401` means the key is missing or wrong.
- A `429` means too many wrong wall codes were tried recently and visitor access
  is paused; the `error` says for how long. Tell the visitor and stop retrying.

## POST /command — make the wall do something

Request body (JSON):

```json
{ "action": "<action name>", "payload": { ...fields for that action... } }
```

All payload fields are strings. Send exactly the fields listed for the action.

<!-- BEGIN:actions (generated from lib/actions.ts by scripts/gen-skill.ts — do not edit by hand) -->

### `set_scene` — Switch the wall to a named scene

Required payload fields: `name`

```json
{"action":"set_scene","payload":{"name":"<name>"}}
```

### `set_color` — Set the dominant color, e.g. #ff3300

Required payload fields: `hex`

```json
{"action":"set_color","payload":{"hex":"<hex>"}}
```

### `trigger_effect` — Fire a one-shot effect

Required payload fields: `name`

```json
{"action":"trigger_effect","payload":{"name":"<name>"}}
```

### `spawn_object` — Add an object with a text label

Required payload fields: `kind`, `label`

```json
{"action":"spawn_object","payload":{"kind":"<kind>","label":"<label>"}}
```

### `play_clip` — Play a video clip by id

Required payload fields: `id`

```json
{"action":"play_clip","payload":{"id":"<id>"}}
```

### Known values (the wall implements exactly these)

- `set_scene` names: `sunset`, `ocean`, `forest`, `night`, `calm`, `party`, `idle`
- `trigger_effect` names: `welcome`, `flash`, `pulse`
- `spawn_object` kinds: `cube`, `sphere`, `capsule`; `label` is any short text
- `set_color` takes any 6-digit hex; e.g. red `#ff0000`, blue `#0044ff`, green `#00cc44`, purple `#8800ff`, gold `#ffb300`, pink `#ff3399`
- `play_clip` ids: none configured yet; do not suggest it

<!-- END:actions -->

### Response

Success (`200`):

```json
{
  "ok": true,
  "message": "The wall is now running set_color.",
  "suggestions": [
    { "say": "make it a night scene", "action": "set_scene", "payload": { "name": "night" } },
    { "say": "do a pulse", "action": "trigger_effect", "payload": { "name": "pulse" } },
    { "say": "put a cube on the wall that says hello", "action": "spawn_object", "payload": { "kind": "cube", "label": "hello" } }
  ]
}
```

**Read the `message` field back to the user, in your own voice.** It confirms
what the wall is doing now. `suggestions` are things the visitor could say next;
each comes with the exact request to send if they pick it. Offer one.

Failure (`400`):

```json
{ "ok": false, "error": "Unknown action \"dance\". Valid actions are: set_scene, set_color, trigger_effect, spawn_object, play_clip." }
```

The `error` text tells you what was wrong (unknown action, missing field, bad
hex colour). Fix the request and retry once; do not read raw error text to the
user unless the retry also fails.

## GET /status — what is the wall doing now?

Returns the current state, for example:

```json
{ "action": "set_color", "payload": { "hex": "#ff3300" }, "at": 1727640000000 }
```

Or `{ "action": "idle" }` if nothing has been sent yet. Use this to answer
"what's on the wall?" without sending a command. It also carries `suggestions`
and an `onboarding` object that repeats the first-contact steps above; follow
it when a visitor has just connected.

## GET /events — did the wall respond?

Returns the last 20 events the installation itself has written, newest first:

```json
{ "events": [ { "id": "…", "type": "ack", "action": "set_color", "at": "…", "data": { "commandAt": 1727640000000 } } ] }
```

An `ack` whose `data.commandAt` matches the `at` from `/status` means the wall
received and executed the latest command. No matching ack after a few seconds
usually means the Unity client is offline; tell the user the wall may be asleep.

## Behaviour notes

- One command at a time. Wait for the response before sending another.
- Colours must be 6-digit hex like `#ff3300`. Convert colour names yourself.
- Prefer `set_scene` for moods ("make it calm"), `set_color` for explicit colours,
  `trigger_effect` for momentary things ("do a flash"), `spawn_object` when the
  user wants something added with a label. `play_clip` has no clips yet.
- Only use the scene, effect and object names listed under "Known values".
