Components
- JIB.Service — the background Windows host. It owns the USB hardware, loads plugins, renders frames, and serves the IPC servers.
- JIB.Configurator — the WinUI 3 desktop app for visual editing. It has no shared DLL with the host; it talks over TCP.
- SimHub.JIB.Plugin — runs inside SimHub.exe and streams telemetry to the host. The one plugin that lives outside the host process.
- StreamDockNative.dll — a C++ passthrough layer for USB HID and SDK communication. It does no rendering.
- Internal plugins — ten providers loaded from
Plugins/: SimHub, Media, Camera, Keyboard, Mouse, vJoy, OBS Studio, HTTP, System Commands, System Monitor.
Topology
The host is the hub. The Configurator and the SimHub plugin are both clients of the host, and neither talks to the other directly.
SimHub plugin
Inside SimHub.exe, on the sim rig PCJIB.Service
Windows host, owns the USB boxesJIB.Configurator
WinUI 3 desktop app, anywhere on the LANBecause each part is a standalone process that only requires a TCP route to the host, the three processes can run on three different machines. There is no shared DLL and no shared filesystem requirement between them.
Ports and protocols
| Port | Protocol | Path | Notes |
|---|---|---|---|
16550 |
TCP, 4-byte length-prefixed JSON | Configurator ↔ Host | Primary IPC. One request per connection. Host events are pushed on 16551-style event port (loopback). |
16551 |
UDP | Discovery | Active request/reply plus a periodic broadcast beacon every 2 s. |
16555 |
TCP, line-delimited JSON | SimHub plugin → Host | Persistent connection with handshake and a 5 s ping/pong heartbeat. |
The Configurator and the host exchange a JSON envelope with ProtocolVersion, MessageType, and CorrelationId; responses add Success, ErrorCode, and ErrorMessage. The SimHub plugin uses raw line-delimited JSON with a handshake of {"Handshake":"JIB.SimHub.Plugin","Version":"1.0"}.
Discovery
The Configurator finds hosts in three ways:
- Local fast-path — if
%TEMP%\JIB.Service.portexists (JSON{"Port":16550}), the Configurator tries127.0.0.1:<port>directly. Deterministic and network-independent. - UDP request/reply — the Configurator broadcasts a
DiscoverRequeston port16551and collects unicast replies for 1.5 s, deduplicated byhost:port. - Periodic beacon — the host also broadcasts
{"Service":"JIB.DeviceHost","Host":"<LAN-IP>","Port":16550}every 2 s as a passive complement.
The host picks its best IPv4 LAN address by scanning active interfaces (prioritizing those with a gateway, excluding tunnels and loopback). 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 are all handled uniformly.
Connecting across the LAN
For a Configurator or a SimHub plugin to reach a host on another machine, the host must be reachable:
- Open
Settingsin the Configurator and enableAllow LAN connectionsunderNetwork access. When disabled, the host listens on127.0.0.1only. - Make sure the Windows firewall allows inbound connections on the relevant TCP ports (
16550,16555) and UDP16551for discovery. - Connect the Configurator to the host's LAN address, e.g.
192.168.1.20:16550, or pick it from the discovered endpoints list.
Multi-machine scenarios
Everything on one PC
The default and simplest setup. The host, the Configurator, and SimHub all run on the same machine; the Configurator connects to 127.0.0.1:16550.
Host on the rig, Configurator at the desk
Run the host on the PC that has the USB boxes (or a small machine bolted to the rig), enable LAN access, and edit from a desktop or laptop on the same network.
SimHub on the racing PC, host elsewhere
Because the SimHub plugin streams telemetry over TCP 16555, SimHub can run on the dedicated racing PC while the host that owns the hardware lives on another machine. Point the SimHub plugin at the host's address.
Headless host
The host can run without a Configurator attached. In alpha, prefer running it in console mode (Host\JIB.Service.exe) rather than as a Windows service, to keep updates, logs, and resets simple.
Rendering pipeline
JIB renders with SkiaSharp on the CPU (no GPU), so it works on machines without a discrete GPU:
Payload → Scene → SkiaSharp raster → JPEG/PNG → device USB
The host uses a single renderer shared between Configurator previews and device frames, plus a shared frame cache, to keep preview and hardware output in sync. An autonomous render loop pre-renders button frames (configurable up to 60 FPS, with delta hashing to skip re-rendering unchanged frames).
Feature transports
How a device feature is driven — via the vendor SDK or directly by JIB (native) — is decided per feature and per device family, not by a single global switch:
- SDK — driven through the vendor SDK or transport.
- Native — driven directly by JIB, typically raw HID or a vendor protocol JIB implements itself.
- Mixed — depends on the model or sub-case.
- Unsupported — not available for that device.
Features tracked this way include Render, Brightness, Led, Input, DeviceConfig, KeyGif, BackgroundGif, BootVideo, and Vibration. The user-facing policy stays simple: SDK only or Hybrid (switch to the native stack only when the runtime judges it complete for the required features).
Dispatch modes
Every action resolves to one of three dispatch modes, in this order of priority: user override on the card, the mode recommended by the plugin, then a host fallback by target kind.
| Mode | Behaviour | Use for |
|---|---|---|
Auto | Uses the plugin recommendation if present, otherwise the host fallback. | General use. |
Simple (pulse) | Emits a single one-shot pulse; no separate release. | Page navigation, mute, system commands. |
Press / Release | Emits Press on press, then Release on release. | Keyboard shortcuts, vJoy holds, push-to-talk. |
The action card shows an Execution selector listing Auto plus only the modes the action actually supports.