Phroller Logo Phroller Companion API
Local: http://127.0.0.1:47321

Scripts, Tools & Automation

The Phroller Companion API runs a local HTTP REST and WebSocket server at http://127.0.0.1:47321. Any programming language, macro keypad, or broadcast tool can interact with your live tabletop session.

1. Python: Procedural Room & Dungeon Generator

Automate map preparation with simple HTTP requests. For example, draw a complete stone room with doorways and place character tokens:

import requests

API = "http://127.0.0.1:47321/v1"
HEADERS = {"Authorization": "Bearer <key>"}

# 1. Draw a 10x8 dungeon room with a south door
requests.post(f"{API}/draw_walls", json={
    "rooms": [{
        "rect": [0, 0, 10, 8],
        "height": 2,
        "color": "#718096",
        "doors": [{"side": "south", "at": 4, "width": 1}]
    }]
}, headers=HEADERS)

# 2. Place character tokens inside the room. Asset ids come from
#    list_assets, or from import_asset for art of your own.
requests.post(f"{API}/place_tokens", json={
    "tokens": [
        {"asset": "fighter_mini", "cell": [3, 4], "label": "Thorin"},
        {"asset": "goblin_mini", "cell": [7, 3], "label": "Goblin Scout"}
    ]
}, headers=HEADERS)

2. Elgato Stream Deck & Macro Pads

Map physical keys to trigger immediate board changes during a game session:

  • Toggle Fog of War: POST to /v1/set_fog with {"covered": true} or {"covered": false}.
  • Snap Camera to Boss Room: POST to /v1/set_camera with {"center": [20, 15], "zoom": 1.4, "target": "user"}. Without "target": "user" it aims the API's own camera, which screenshots use and the player never sees.
  • Open New Scene: POST to /v1/new_scene with {"name": "Ambush Site"}.
  • Undo Last Action: POST to /v1/undo_last with empty JSON {}.
# 1-click Stream Deck curl command to uncover the active map
curl -X POST http://127.0.0.1:47321/v1/set_fog \
  -H "Authorization: Bearer <key>" \
  -H "Content-Type: application/json" \
  -d '{"covered": false}'

3. OBS Browser Source & Live Stream Overlays

Connect any OBS browser source to ws://127.0.0.1:47321/v1/events?token=<key> to display live dice rolls on your broadcast:

const token = 'YOUR_API_KEY';
const ws = new WebSocket(`ws://127.0.0.1:47321/v1/events?token=${encodeURIComponent(token)}`);

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === 'dice.rolled') {
    const roller = msg.roller || 'Player';
    document.getElementById('stream-banner').innerText = `🎲 ${roller} rolled ${msg.total}!`;
  }
};

4. Every Board Command

Each one is POST /v1/<command> with a JSON body, and an MCP tool of the same name. This list is read from the OpenAPI spec, which the app generates from its own commands — see the interactive reference for every field.

Command Kind Summary
Loading the commands…

5. Coordinates & Geometry Reference

  • Grid Cells: Coordinate [x, y] where tokens stand. 1 cell = 60 world pixels.
  • Points: Coordinate [x, y] at cell corners. Walls, doors, and bounding rectangles run on points. For example, a room covering cells (0,0) to (4,3) has rectangle [0, 0, 5, 4].
  • Hex Maps: Pointy-top offset coordinates where odd rows are shifted half a cell. Points remain a square lattice.
  • Colors: Hex colors formatted as #RRGGBB or with alpha #AARRGGBB.

6. Model Context Protocol (MCP)

The same server is an MCP endpoint at http://127.0.0.1:47321/mcp (streamable HTTP). Every board command above is a tool, and the server's instructions tell the client how the board works:

  • How-to questions are answered from the app's own Help. get_help searches it and returns the steps with every button named as it reads on screen; show_help walks the player through a page on their own screen.
  • The client has a camera of its own. screenshot and set_camera aim it without moving the player's view, and every answer says where it points, including looking, the compass direction at the top of the picture. When something is out of view, the client is told to move the camera and look again.
  • Mistyped fields are reported. A key a command did not use comes back in warnings, with the field it was probably meant to be.
  • Long formats are in guides. get_guide serves the reference for board games, smart objects and every command.
# Connect with Claude Code CLI
claude mcp add --transport http phroller http://127.0.0.1:47321/mcp \
  --header "Authorization: Bearer <key>"

Real-time WebSocket Events

Stream real-time dice rolls, token movements, map state changes, and scene switches directly to your stream overlays, bots, or companion screens.

Connection Protocol

Connect a WebSocket client to ws://127.0.0.1:47321/v1/events. If your client cannot set an Authorization: Bearer <key> header (e.g. browser WebSocket API), supply the token in the query string:

ws://127.0.0.1:47321/v1/events?token=<key>

Upon connection, the server immediately returns a welcome handshake:

{
  "type": "hello",
  "apiVersion": "1"
}

Event Catalog

Every event carries its type and an at timestamp. Bursts are coalesced, so a drag arrives a few times a second. Events name what changed; read the details with the commands.

Event Type Carries
Loading the events…

Browser / Node.js Client Example

const token = 'YOUR_API_KEY';
const socket = new WebSocket(`ws://127.0.0.1:47321/v1/events?token=${encodeURIComponent(token)}`);

socket.addEventListener('open', () => {
  console.log('Connected to Phroller Companion Events!');
});

socket.addEventListener('message', (event) => {
  const data = JSON.parse(event.data);
  console.log('Received Phroller event:', data.type, data);

  if (data.type === 'dice.rolled') {
    console.log(`Rolled ${data.total}!`, data.dice);
  } else if (data.type === 'tokens.moved') {
    console.log('Tokens moved:', data.tokens);
  }
});

socket.addEventListener('close', () => {
  console.log('Disconnected from Phroller Companion Events.');
});
Open in New Tab
Loading OpenAPI 3.1 specification...