# Making routers: start here

For people who connect a game to Fusion, and for the AI agents they work with. Read this page
first; it says which other page you need.

A **router** connects one game to Fusion. It splits the game into **blocks** (its world, its
characters, its NPCs) that players snap together with blocks of other games, with no code: cards,
press Play. One router per game; every fusion with that game reuses it.

## Why make a router instead of a two-game mod

Today a fusion is a hand-built mod for one pair of games: copy SkyCraft, rename the host, write
the link, the collision, the camera sync, the frame pacing, an installer, and publish a repo. The
player then installs a mod loader, a launcher, Java, a modpack, and starts both games in order.

| | A two-game mod | A Fusion router |
|---|---|---|
| What you write | both halves: link, collision field, camera sync, compositing, input, pause, installer | only what's particular to your game: which object is the player, which are NPCs, how to get past the menu. Mostly data in `router.toml` |
| Size | SkyCraft is about 890 KB of code | VEIN's router is 25 lines of data and 36 lines of Lua; "Minecraft in VEIN" is a 15-line scenario |
| Which games it fuses with | one other game | every game that has a router, in any number, picked block by block |
| Minecraft's side | yours to fork and maintain | done: Fusion's Fabric kit is SkyCraft's mod, kept up to date |
| Players install | a loader, a launcher, Java, files in the right folders, both games started in order | Fusion, then **Play**: one-click setup installs the loaders and your router |
| Game updates | it breaks, and someone rediscovers the game | `tested_builds` disables it cleanly; `fusion-cli game diff` lists what the update renamed |
| Testing | look at the screen | `router check` and `router conform` measure it in numbers (picture lag in frames, collision, NPCs, sleep and wake) |
| The next person | starts again from the source | starts from your router (`router get`), its `notes.md` and `MODLOG.md`, and sends you improvements |

## Your path

Run `fusion-cli router recon <the game's folder>` first. It reads only file names and says the
engine, which path fits, whether there's anti-cheat, and whether the game already has a router.
**Bringing a passthrough mod you made?** Run `fusion-cli port <your mod's folder>` instead: it
writes the whole port's plan (`PORT.md`), router and scenario ([`porting.md`](https://steonmod.com/docs/porting)).

| What you have | What you make | Read |
|---|---|---|
| An **Unreal** 4 or 5 game | data (and maybe a little Lua) on Fusion's Unreal kit | [`agent/unreal.md`](https://steonmod.com/docs/agent-unreal), [`router-api.md`](https://steonmod.com/docs/router-api) |
| A **Unity IL2CPP** game (`GameAssembly.dll` in its folder) | data (and maybe Lua) on Fusion's Unity kit | [`agent/unity.md`](https://steonmod.com/docs/agent-unity), [`router-api.md`](https://steonmod.com/docs/router-api) |
| **Your own mod already in the game**: a BepInEx or MelonLoader plugin (Unity Mono), an SKSE/F4SE/NVSE plugin, a Source server plugin, an injected DLL | keep your mod; replace its link with Fusion's **guest SDK** (C# `FusionGuest.cs`, C/C++ `fusion_guest.h`) | [`agent/sdk.md`](https://steonmod.com/docs/agent-sdk), [`porting.md`](https://steonmod.com/docs/porting), [`guest-sdk.md`](https://steonmod.com/docs/guest-sdk) |
| An **open-source** game, a rewrite or a recomp | link the guest SDK into its source (Rust, Bevy, C, C#) | [`guest-sdk.md`](https://steonmod.com/docs/guest-sdk) |
| **Minecraft** | nothing: its router is in Fusion; players pick their own modpack on its card | |
| A game with **anti-cheat** | only if its own launcher has an official anti-cheat-off mode (`[router.anticheat]`); otherwise it can't come in | [`block-manifest.md`](https://steonmod.com/docs/block-manifest) |

Already made a passthrough mod (a SkyCraft port, a ReShade bridge)? [`porting.md`](https://steonmod.com/docs/porting) maps each part
of it to Fusion: most of it is no longer yours to maintain.

## Set up

1. Install Fusion. Its developer tool is `fusion-cli.exe` in Fusion's `bin` folder
   (`%LOCALAPPDATA%\Programs\Fusion\versions\<version>\bin`; add it to your PATH).
   `fusion-cli where` prints every folder you need (docs, the agent pack, the SDK files, routers).
2. Make a folder for your work, and in it run `fusion-cli agent install`. Your AI agent then knows
   Fusion's commands and rules (a Claude Code skill, and a section of `AGENTS.md` for Codex, Cursor,
   Copilot and Gemini CLI). Your own text in `AGENTS.md` stays.
3. Your routers live in `routers/<id>/` in that folder. Fusion's commands read them first, then
   the routers installed in Fusion.

## The loop

1. **Look first.** `fusion-cli router recon <game folder>`. If the game has a router, improve it
   instead of making a second one: `fusion-cli router get <id> --out work/<id>`, change it,
   `router check` it, then `fusion-cli router propose work/<id> --message "what and why"` and send
   the file to its author.
2. **Start.** `fusion-cli router new <id> --name "<Name>" --kit unreal|unity|sdk (--steam-app N | --exe <path>)`
   writes `routers/<id>/`: `router.toml` (the blocks), `router.lua` (kits), `MODLOG.md` (what
   changed and why), `notes.md` (gotchas for the next person).
3. **Ask the game, don't guess.** With the game running and Fusion closed:
   `fusion-cli game find <text> --game-id <id>`, `game classes`, `game objects <Class>`,
   `game inspect <object>`. Or open Fusion, play the router's blocks and press **F4** (Router Studio):
   click "This is the player", "These are NPCs", and save.
4. **Write the data**, then Lua only where data can't say it (a menu to click through).
5. **Check.** `fusion-cli router check routers/<id>`: a few lines, each failure with its fix; exit
   code 0 = pass. `--live` has the running game try the router.
6. **Measure.** `fusion-cli router conform routers/<id> --start`: Fusion's side, in numbers. It
   starts the game, checks every port the router promises, the picture's lag behind Fusion's
   camera, requests it can't do, and sleep and wake. Publishing needs a pass.
7. **Play it.** Make a scenario (below) and play it in Fusion. **F7** shows collision, **F8**
   entities, **F6** cost, **F4** Router Studio.
8. **Write it down.** A line in `MODLOG.md`; anything surprising in `notes.md` (what you saw →
   why → the fix), with the game build that worked.

Stop after three identical failures: write what you know in `MODLOG.md` and change approach.

## Blocks, and what your router must do for each

Players combine blocks; ports say what flows between them. Fusion wires matching ports by itself.

| Block `kind` | What it is | It gives / needs | What your router does |
|---|---|---|---|
| `world` | the place everyone stands in | gives `layer:color+depth`, `collision` | the game draws its world **from Fusion's camera**, and sends its ground and walls |
| `character` | someone the player plays | needs `input` (and `collision` if it walks on another World), gives `pose` | moves its character from Fusion's controls; says where its feet and eyes are |
| `npc_group` | enemies, animals, vehicles | gives `entities`, lists `actions` | lists them a few times a second (id, kind, position, health); does `remove`, `set_health`, `move_to`... |
| `items`, `system` | things to hold; weather, money | gives `state`, `events` | (v0: few routers have these yet) |

One scenario has one World and at most one played Character; any number of the rest. A block
that isn't a World plays in Fusion's own playground, so you can test an NPC group without a world.

Everything crosses in **Fusion's space**: meters, Y up, right-handed, -Z forward. Kits convert from
the `units` your router declares; with the SDK you convert at your game's edge ([`agent/sdk.md`](https://steonmod.com/docs/agent-sdk)).

## A scenario

A scenario is the fusion players press Play on. It names blocks; Fusion does the wiring:

```toml
[scenario]
name = "Minecraft in VEIN's World"
description = "Play as the Minecraft player in VEIN Demo's world."

[[block]]
use = "vein.world"

[[block]]
use = "minecraft.player"
```

Put it in a `scenarios/` folder and check it with `fusion-cli check-scenario scenarios/<file>.toml`.
Players make the same thing with cards in Fusion (**Create → Build a scenario**).

## Test without the game

- `router check` needs no game at all; `router conform` needs it running.
- Fusion's test game (`fake-guest`) and the SDK's example worlds behave like games: try a draft
  on them first.
- Record what your game sends once (start Fusion with `-- --record=<folder>`), then
  `fusion-cli replay <folder>/<router>.fusionrec` plays it back with no game running, for testing
  addons, Devices and Experiences in seconds.

## Publish

1. `fusion-cli router conform routers/<id> --start` must pass (it writes `conformance.toml`).
2. `fusion-cli package router routers/<id> --out <id>.fusion` checks and signs it. The publish
   check refuses game files, extracted game data, decompiled code and memory addresses.
3. Share the `.fusion` file (players double-click it, or drop it on Fusion), or send it to a
   content hub.

Trust: a router of data and Lua can come from anyone. A router that carries program files (the
DLL of an SDK plugin) is shared only from **verified authors**. Credit what you build on:
`contributors`, `based_on`, and keep the licenses of code you reuse (SkyCraft is MIT).

## Rules

- Single-player and offline only. Never touch anti-cheat, online modes or copy protection; the one
  exception is a game's own official anti-cheat-off mode.
- Never ship game files, extracted assets, decompiled code or encryption keys. Reading the
  player's own installed files at runtime for lists and names is fine (`[[block.content]]`).
- Never focus a game window or send it input while someone is using the PC. Stop processes by id,
  never by name.
- No Nintendo or Take-Two games (Fusion's blocklist).

## Where to read more

| Page | |
|---|---|
| [`porting.md`](https://steonmod.com/docs/porting) | from your passthrough mod to a router, part by part |
| [`router-api.md`](https://steonmod.com/docs/router-api) | the kits' data (`[block.bind]`) and Lua (`Router.block`, `Game.*`) |
| [`block-manifest.md`](https://steonmod.com/docs/block-manifest) | every `router.toml` field, ports, placeholders, setup recipes |
| [`guest-sdk.md`](https://steonmod.com/docs/guest-sdk) | the guest SDK: Rust, Bevy, C/C++, C# |
| [`protocol.md`](https://steonmod.com/docs/protocol) | the protocol under the SDK and kits, and the questions tools ask a game |
| [`packages.md`](https://steonmod.com/docs/publishing), [`trust.md`](https://steonmod.com/docs/trust) | packages, signing, trust tiers |
| [`lua-api.md`](https://steonmod.com/docs/lua-api), [`devices.md`](https://steonmod.com/docs/devices) | addons, Devices and Experiences built on your blocks |
| `agent/` | the agent pack: [`SKILL.md`](https://steonmod.com/docs/agent-pack) and one page per path (`fusion-cli where` shows it) |
