Bridge Mods
compat JSON can only adjust things that already exist — a registered KeyMapping, a dispatched key, an open screen. If a mod grew its own input system, it has to be wired in on the Java side, and that is a bridge mod. This page answers "do you need code at all" and then gives you a table of the five techniques; the setup steps, the interface details, the five official implementations and the ecosystem list each get their own page.
Section: Overview · Setup & lifecycle · Interfaces · Implementations · Who uses the API
Setup & lifecycle
Gradle dependency, SPI registration, the order of the six callbacks, which folder your JSON lands in, and how to lay out a multi-loader project.
Build one →
Interface reference
Signatures for all 13 public types, threading rules, action-id formats and version changes.
Look it up →
Implementations
Epic Fight, Create, Exposure, EMI and vehicles taken apart one by one, plus code for all five techniques.
Read the code →
Who uses this API
Which mods really depend on control-flex-api, which are only adapted, and the versions each one needs.
See the list →
First: do you actually need code?
| Compat JSON can | Only a bridge mod can |
|---|---|
| Place registered keys on Main / Screen / Overlay | Make keys that never registered a KeyMapping appear in the binding list |
| Choose the dispatch channel (including the GLFW polling mirror) | Reach mods that call GLFW.glfwGetKey directly (the GLFW layer cannot be injected) |
| Suppress actions by main-hand item plus player state | Push the mod's runtime state into Control Flex for use as a condition |
| Phase persistence, ignored keys, tips, per-screen stick parameters | Announce that a mod has taken over an overlay or the camera, so stick and look behavior can switch |
| Fall back to virtual keyboard / mouse for mods that only see physical keys | Run fully custom logic off the stick axes (vehicle steering, camera), or forward an action into the mod's own function |
One-line test: if the mod's keys show up under Key Mapping → that mod, you do not need a bridge; if they do not, you do. The three tools are cumulative — auto-discovery → compat JSON → bridge; do not skip the first two and start writing code.
Five techniques at a glance
A bridge is not one technique but five answers to five problems. Work out which one your target mod poses, then jump to the official implementations for the full code.
| What the target mod does | What the bridge has to do | Reference implementation |
|---|---|---|
| Keeps its bindings in its own config and never registers a KeyMapping | Register pseudo KeyMappings so auto-discovery sees them, then forward the press into the mod's own function | cfx-compat-emi |
Reads key state via InputConstants / ControlsUtil |
Inject once on its predicate and merge the analog-movement impulses into the answer | cfx-compat-create |
Calls GLFW.glfwGetKey directly, never going through InputConstants |
Put a mixin on the mod's own read path and answer "is it held right now" | cfx-compat-vehicles |
| Has runtime state that changes what the keys mean (battle mode, vehicle mode) | Push that state as modId:state so compat JSON can use it as a condition |
cfx-compat-epicfight |
| Draws its own overlay that takes the camera and cursor but is not a Screen | Notify foreground and background as a matched pair | cfx-compat-exposure |
One case sits alongside these five: the mod takes over the render camera (TPS battle view, target lock). Then you also implement ICameraLookConsumer and hand the look delta to whoever owns the camera, or the stick will not turn the view. The Epic Fight bridge does case 4 and this one at once.