Cross-platform frameworks (React Native's legacy bridge, Flutter platform channels) move every call between the JS/Dart layer and native code across a queue that must serialize the payload to a wire format, hop threads, and deserialize it. Each crossing ("packet") costs a fixed setup fee plus a per-byte encoding fee:
cost(batch) = F + n · s · k
F = fixed bridge overhead (~0.9 ms)
n = messages in the batch
s = bytes per message payload
k = serialize/deserialize cost per byte (~0.0006 ms/B)
Batching amortizes F across many messages — bigger batches raise throughput per crossing. But a batch only flushes once it hits the batch size cap or the oldest queued call reaches the batch window, so a message waits in queue before it even starts crossing. And because the native/UI thread processes an arriving batch synchronously, a crossing that costs more than one frame's budget (~16.7 ms at 60 fps) blocks rendering for that frame — a dropped, janky frame.
- Call rate — how many native calls the JS side fires per second.
- Payload size — bytes serialized per call (a JSON object, an image buffer reference, etc.).
- Batch size cap — max messages coalesced into one crossing; 1 = no batching.
- Batch window — max time a call waits for the batch to fill before it flushes anyway.
The top lane shows queued calls stacking on the JS pad, coalescing into a crossing packet (orange = under budget, red = jank) that flies to the native pad. The bottom-left chart plots each delivered call's real latency against the 16.7 ms frame-budget line — drag across it to inspect any past crossing. The bottom-right panel breaks the current slider settings down into fixed-overhead vs. serialization cost, live, even while paused.
Note: latency here is computed analytically as queue-wait + cost(batch) — the true bridge-crossing time from the formula above — rather than from the on-screen flight duration. The flight animation uses its own comfortable, clamped pacing (0.35–2.2 s) purely so a crossing is watchable; tying the latency stat to that clamp would make "Avg latency" mostly reflect animation pacing instead of the F+n·s·k model advertised above (verified numerically: at defaults the clamped flight is ~340× longer than the real ~1 ms cost).