BoredBundle Play BoredBundle
Modding guide · Godot 4

Create a BoredBundle mod

A BoredBundle mod combines a Godot host screen with a small browser app that runs on each player's phone. The SDK handles players, connections, reconnection, and message delivery; your mod supplies the game rules and interface.

Before you begin: install Godot 4 and start a new Godot project whose project root is also your mod root. You will need the addons/bored_bundle/ folder from the BoredBundle source tree.
Create the project

Add the SDK, a manifest, host-side scenes and scripts, and a phone web app.

Write the game

Extend the SDK classes and exchange game-specific actions and messages with phones.

Build the phone app

Compile its static HTML, CSS, and JavaScript into the directory named by the manifest.

Validate and package

Use the SDK's Godot editor tools to produce a distributable folder.

1. Set up the project

Create this basic layout. Only src/ is packed into the mod's PCK; phone files and content folders are shipped as loose files.

my_mod/
├── project.godot
├── game.json
├── addons/
│   └── bored_bundle/
├── src/
│   ├── my_game_manager.gd
│   ├── my_play_screen.gd
│   └── play_screen.tscn
├── web_app/
│   └── dist/
│       └── index.html
├── avatars/          # optional player avatars
├── assets/           # optional images, music, etc.
└── data/             # optional game data
  1. Copy addons/bored_bundle/ into the project.
  2. In Godot, open Project → Project Settings → Plugins and enable Bored Bundle SDK.
  3. If your lobby scene uses QRCodeRect, also copy addons/qr_code/.

The plugin installs the BoredBundle autoload and adds validation and build commands to the Project → Tools menu.

2. Describe the mod in game.json

The manifest sits at the project root. Paths below are authoring paths; the builder rewrites files under res://src/ into the final mod namespace.

{
  "schema_version": 1,
  "min_host_version": 1,
  "min_sdk_version": 1,

  "game_id": "MyGame",
  "display_name": "My Game",
  "description": "A short description of the game.",
  "kind": "code",

  "game_manager_script": "res://src/my_game_manager.gd",
  "play_screen_scene": "res://src/play_screen.tscn",
  "intro_scene": "",

  "web_app_dir": "web_app/dist",
  "avatar_base_path": "avatars",
  "data_dir": "data",
  "assets_dir": "assets",

  "min_players": 2,
  "max_players": 8,
  "supports_cpu": false
}

game_id must be a valid Godot identifier: use letters, numbers, and underscores, do not begin with a number, and do not use spaces. Set min_sdk_version to the oldest SDK that provides every API your mod calls.

3. Build the Godot host

Your manager owns the rules. Extend the SDK manager, call the parent _ready(), listen for the start request, and handle actions sent by phones.

# src/my_game_manager.gd
extends "res://addons/bored_bundle/runtime/game_manager.gd"

func _ready() -> void:
    super._ready()
    start_game_requested.connect(_start_game)

func _start_game() -> void:
    game_active = true
    broadcast_to_all({"type": "game_started"})

func handle_game_action(player_id: String, action: String, data: Dictionary) -> bool:
    if action == "answer":
        broadcast_to_all({
            "type": "answer_received",
            "player_id": player_id
        })
        return true
    return false

func send_game_state_to_player(player_id: String) -> void:
    # Restore important state when this player reconnects.
    send_to_player(player_id, {"type": "game_state", "active": game_active})

The play-screen script should extend the matching SDK screen:

# src/my_play_screen.gd
extends "res://addons/bored_bundle/runtime/play_screen.gd"

Attach that script to the root of play_screen.tscn. Build the host UI as you would any Godot scene. These are the core manager APIs:

Messaging

send_to_player() and broadcast_to_all()

Players

get_player(), get_players(), and get_playing_players()

Lifecycle

apply_settings(), send_game_state_to_player(), and run_game_cleanup()

Scenes

change_scene() plus the built-in pause overlay

For editor previews without a running host, use BoredBundle.set_preview_players(). Network sends safely return false when the standalone project is not attached to the engine runtime.

4. Create the phone app

The phone interface can use any web framework—or none—as long as its production build is static and lands in web_app/dist/ (or the directory configured by web_app_dir). It must connect through the BoredBundle web client, render host messages, and send player actions.

import { createWebAppClient } from "@bored-bundle/web-app";

const client = createWebAppClient();

client.on("server_message_received", (message) => {
  if (message.type === "game_started") showGame();
});

document.querySelector("#answer").addEventListener("click", () => {
  client.sendAction("answer", { value: "my-answer" });
});

client.connect();

If you are developing inside the BoredBundle source repository, install the shared package into your web project with a relative path:

cd path/to/my_mod/web_app
npm install path/to/web_packages/web-app
npm run build

The client manages the WebSocket handshake, persistent player identity, join code, and reconnection. Host messages you invent and phone actions you send form your game's own small protocol.

5. Validate, build, and install

  1. Build the phone app and confirm web_app/dist/index.html exists.
  2. Let Godot finish importing any images, audio, and fonts used under src/.
  3. Run Project → Tools → Validate Bored Bundle Mod.
  4. Run Project → Tools → Build Bored Bundle Mod.

The finished distributable is written to build/MyGame/. It contains the rewritten manifest, MyGame.pck, the built phone app, and any loose data, asset, or avatar folders.

You can also build from the command line:

godot --headless --path /path/to/my_mod \
  --script res://addons/bored_bundle/tools/build_mod.gd -- \
  res:// /path/to/my_mod/build

To test the result, copy the entire build/MyGame/ folder into the BoredBundle executable's user://mods/ directory. Publish that same folder through Workshop when it is ready.

Do not bundle another SDK copy. A shipped code mod contains its own src/ PCK and loose web/content files. The BoredBundle executable supplies the SDK at runtime.

SDK feature versions

Raise min_sdk_version only when you use a feature introduced by that version. Hosts reject incompatible mods before loading their scripts.

SDK 3

Sub-mod content overlays and content-root helpers.

SDK 4

Drawing sessions, drawing canvas, and quit helpers.

SDK 5

Player-aware phone controller sessions.

SDK 6

Shuffled background-music playlists.