Skip to content

External Web UI

noteMASTER11 edited this page Jul 23, 2026 · 10 revisions

External Web UI

Experimental feature. Connected phone depends on BeamNG.drive's External UI transport, the local network, operating-system firewall policy, and browser behavior. Keep the in-game phone available as a fallback.

TaxiDriver can mirror its live phone interface to another device on the same trusted local network. The external page is interactive: accepting orders, changing screens, opening settings, and other supported actions operate on the same authoritative Lua state as the in-game UI App.

Requirements

  • BeamNG.drive and TaxiDriver must remain running.
  • The computer and phone must be on the same LAN or Wi-Fi network.
  • TCP port 8085 must be free on the computer's selected private IPv4 address.
  • BeamNG.drive must be allowed to accept private-network traffic through the operating-system firewall.
  • Guest/client isolation must be disabled on the router or access point.
  • Connected phone must be enabled for the current TaxiDriver UI App session.

If port 8085 is occupied, or the game is denied network access, the QR URL cannot open from another device. A working 127.0.0.1 page does not prove that the LAN address is reachable.

Connecting

  1. Open TaxiDriver settings.
  2. Expand Connected phone.
  3. Enable Share over local network.
  4. Wait until the LAN address and QR code appear.
  5. Scan the QR code with a phone connected to the same trusted network.
  6. Keep the game running while the external page loads its interface, sounds, live state, and map data.

The feature is deliberately off by default on every UI App start. Enabling it is session-only; it is not restored from settings.json.

Connection architecture

Phone browser
  → http://<private-ip>:8085
  → BeamNG native LAN listener, when reachable
     OR TaxiDriver non-blocking LAN → loopback byte proxy
  → BeamNG bng-ext-app-v1 WebSocket
  → TaxiDriver GE Lua state

TaxiDriver 3.3.0 Beta starts BeamNG's native server on any:8085 and then probes the chosen private address. A reachable native endpoint is used directly. If BeamNG created only a loopback listener, TaxiDriver starts a bounded non-blocking TCP proxy on <private-ip>:8085 and forwards raw bytes to 127.0.0.1:8085. The proxy is transparent to both HTTP and WebSocket traffic; it does not run a second UI state or gameplay server. Existing firewall permission for BeamNG.drive.x64.exe still controls whether another device can connect.

Windows IPv4 discovery

BeamNG 0.38.6 may return 127.0.0.1 and an incomplete adapter list even though Windows has a usable Wi-Fi/Ethernet address. TaxiDriver therefore evaluates multiple sources:

  1. BeamNG's adapter list;
  2. the address returned by the native server;
  3. the local address selected by a UDP route probe, which sends no payload;
  4. all IPv4 results from LuaSocket gethostname() + Winsock getaddrinfo();
  5. the previously confirmed address from lan.json, when present.

Loopback, APIPA, malformed, and non-private addresses are rejected. Every remaining candidate must pass a real bind test. Physical Wi-Fi/Ethernet descriptions are preferred, common VPN/virtual adapters are penalized, and private-subnet/source scores break remaining ties.

flowchart TD
  Start[Enable Share] --> Server[Start native any:8085 server]
  Server --> Collect[Collect candidates from five sources]
  Collect --> Filter[Private IPv4 validation]
  Filter --> Bind[Per-address bind test]
  Bind --> Rank[Rank physical/source/subnet signals]
  Rank --> Winner{Winner found?}
  Winner -->|yes| Probe{Private endpoint reachable?}
  Probe -->|yes| Native[Use native listener]
  Probe -->|no| Proxy[Bind LAN proxy to loopback listener]
  Native --> QR[Save identity and show QR]
  Proxy --> QR
  Winner -->|no| Diagnostic[Hide empty QR and show diagnostic]
Loading

Pairing identity

TaxiDriver stores a stable random token and the last selected LAN address in:

current/settings/TaxiDriver/lan.json

The file is written only after startup confirms a usable LAN address. Deleting it forces complete discovery and generates a new token. Changing the toggle normally keeps the token. The token prevents accidental use of an incomplete URL, but it is not a substitute for network isolation or HTTPS. Enable the feature only on a trusted local network and do not publish the URL.

Loading and synchronization

The external page has a detailed startup loader for:

  1. game connection;
  2. application runtime;
  3. interface and cached sounds;
  4. live TaxiDriver state.

Refreshing the page requests the current authoritative state again instead of creating a new shift. The external client sends heartbeats; the in-game HUD reports whether a phone is connected. While an external client is active, the in-game app can collapse to a phone button and can still be reopened as a fallback.

Since version 2.23.0, the lightweight external bootstrap explicitly subscribes its WebSocket connection to BeamNG GUI hooks before requesting the first TaxiDriverHUDState. This prevents a connection from reaching the Live trip state stage while silently discarding the state event.

Version 3.0.0 Beta adds an epoch and revision to the HUD stream. Periodic changes are sent as TaxiDriverHUDPatch packets with a required baseRevision. A client rejects duplicate, delayed, or discontinuous patches and requests a complete snapshot automatically. The same mechanism prevents order, trip, and settings screens from diverging between the in-game UI App and Connected Phone.

Version 3.4.0 Beta moves Connected Phone behind optionalLanBridge.lua. The core taxi extension can load and run even if LAN/socket support is unavailable. LAN calls, pairing-identity writes, and mission shutdown are failure-contained, and the server is restarted on the next mission only when sharing remains enabled.

Periodic HUD packets now build a fast scalar state. Offers, shift history, Fleet drivers, garage previews, and settings are included only after an explicit full-state event or when their owner reports a real collection change. This reduces Lua allocation, JSON encoding, WebSocket traffic, and browser merge work without changing epoch/revision recovery.

The Connected Phone layout has dedicated responsive rules rather than inheriting the UI App dimensions. It supports phone and tablet portrait layouts, short landscape screens, safe-area insets, wide two-column order lists, and a persistent app bar.

External map

The browser cannot reuse the native CEF minimap canvas directly, so TaxiDriver exports:

  • the complete available navigation-road graph, chunked to avoid one large UI message;
  • the active ground-marker route;
  • the live positions of player-owned fleet taxis as purple markers;
  • terrain/minimap tile metadata when the map provides it;
  • player position and heading snapshots.

In 3.4.0 Beta, the complete road set is prepared by a coroutine rather than a synchronous level-wide scan. The builder yields after every 500 examined road links, resumes on later game updates, discards stale work after a level or terrain-setting change, and begins normal road-chunk publication only after a consistent build completes.

The external canvas caches the complete road set, indexes it spatially, follows the vehicle arrow, rotates with heading, and draws owned taxis from the authoritative fleet snapshot. Its speed-sensitive zoom is tuned separately from the in-game minimap: it starts closer, eases outward gradually, interpolates camera radius smoothly, and caps the high-speed range so local roads remain useful on a small phone canvas. Fleet monitoring keeps map publication active even without a personal route. The phone page intentionally has no Minimize control.

Performance and battery controls

Connected Phone settings expose:

Control Effect
External map Disables route-map data and canvas work while preserving the rest of the app
Terrain layer Omits terrain metadata and terrain drawing while retaining roads and route guidance
Eco Up to 6 canvas frames/s, 0.5-second vehicle snapshots, 1× canvas pixel ratio
Balanced Up to 15 canvas frames/s and 0.25-second vehicle snapshots
Smooth Up to 30 canvas frames/s and 0.125-second vehicle snapshots

The browser redraws only after meaningful vehicle, heading, route, speed, or camera changes and becomes idle when the rendered map is stationary. Lua remains authoritative for whether a navigation route is active; hiding the in-game CEF layer must not freeze the independently visible phone map.

Audio on iPhone and other mobile browsers

Connected Phone uses one Web Audio context with predecoded embedded sounds. This avoids the iOS failure mode where a manual Test sound works during a tap but later game-event sounds are assigned to other HTML Audio elements that Safari has not unlocked.

After opening or reloading the page, tap anywhere inside TaxiDriver once. Eligible events received before audio is ready are retained in a bounded queue. Audio is also resumed when Safari returns to the foreground, and rapid events can overlap instead of cutting each other off.

Map completeness still depends on the road graph and minimap assets supplied by the current level.

Port and firewall troubleshooting

The page works on 127.0.0.1 but not on the phone

Check all of the following:

  1. The QR URL uses the computer's private address, for example 192.168.x.x, not 127.0.0.1.
  2. TCP port 8085 is not already used by another process.
  3. BeamNG.drive has inbound access on Private networks in Windows Firewall or the installed security suite.
  4. Both devices are on the same subnet, not separate guest and main Wi-Fi networks.
  5. The router does not enable AP isolation, client isolation, or wireless isolation.
  6. VPN, virtual-adapter, and endpoint-security software is not intercepting local traffic.

The detailed loader reports an asset failure

  • Reload the UI App and generate a fresh QR page.
  • Verify there is only one TaxiDriver installation.
  • Clear the phone browser cache for the LAN address.
  • Confirm that taxidriver.zip contains ui/modules/apps/TaxiDriverHUD/external/.
  • Version 3.0.0 Beta appends a build revision to external assets; after replacing the ZIP, restart BeamNG and load the newly generated QR URL.

The loader stops at Live trip state

  • Install TaxiDriver 2.23.0 or newer. Earlier lightweight loaders could connect and send Lua commands without subscribing to returned GUI-hook events.
  • Reload the page after the current level and TaxiDriver UI App have finished loading.
  • Search beamng.log for taxiDriver or taxiDriverLan errors and confirm that only one TaxiDriver version is active.

The URL is empty or the toggle returns to off

TaxiDriver could not start the native External UI server or select a bindable LAN address. Version 3.2.1 Beta hides the empty QR container and shows the immediate diagnostic in Settings. Search beamng.log for [TaxiDriver] area=lan and inspect native_server_started, adapter_discovery, route_discovery, hostname_discovery, address_candidate, address_selected, and external_ui_unavailable. A failed server start can mean port 8085 is occupied; zero viable candidates means Windows/BeamNG did not expose a private bindable IPv4.

Security and limitations

  • Transport is plain HTTP/WebSocket and is intended only for a trusted local network.
  • The pairing token is visible in the QR URL and browser history.
  • No cloud relay, public server, telemetry upload, or third-party service is used.
  • Connectivity can be affected by BeamNG updates because the feature relies on the game's External UI protocol.
  • Mobile-browser autoplay policy still requires one interaction after opening or reloading the page; tap inside TaxiDriver once to unlock event audio.

Clone this wiki locally