Skip to content

Known Issues

Tracked footguns the bridge plugin currently has. Each entry lists the platform / UE version where it bites, the symptom, and the recommended workaround.

UE 5.8

The plugin is compile-verified on both UE 5.7 and 5.8. The UE version field below marks where each issue was observed (mostly 5.7). Status of the two macOS engine regressions on UE 5.8 (PIE-tested 2026-06-25 on UE 5.8.0):

  • Transparent pixels render opaquestill broken on 5.8 (not fixed; the Slate/Metal compositor still drops CEF surface transparency). See Transparent HUD.
  • CEF keyboard focusnot yet re-tested on 5.8; assume still present until confirmed.
  • Native web view sizing / positioningpresent on both 5.7 and 5.8 (identical code in ApplePlatformWebBrowser.cpp). No longer compensated inside the plugin; see the entry below.

To re-check on 5.8, run ./launch-project.sh (the SampleProject defaults to 5.8). Issues whose cause is architectural (Slate clip, content-only Live Coding) are assumed to persist on 5.8.

Mac UE 5.7 chat keyboard cannot focus

  • Platform: macOS
  • UE version: 5.7
  • Tags: mac, ue57, keyboard, chat, focus

Symptom

Pressing a key while the CEF browser layer is focused does not produce keystrokes inside the HUD. Both Slate-focus injection and Carbon window capture fail.

Cause

Engine regression in 5.7's WebBrowser widget on macOS. Slate focus is not forwarded to CEF; the focused element does not receive WM_CHAR equivalents.

Workaround

Use click-to-type: route a button/click event from BP to the React side, then have React open an <input> with autoFocus. Do not invest in Keyboard Binding wiring on Mac UE 5.7 — it will not work.

macOS runtime-mounted display-only HUD steals focus

  • Platform: macOS
  • UE version: 5.7
  • Tags: mac, ue57, focus, wasd, runtime, display-only, cursor

Symptom

Mounting a display-only Web HUD layer (bInteractive = false) at runtime in a possessed game world — e.g. opening a panel on a keypress — makes the OS mouse cursor appear and drops held movement keys: WASD stop registering until you release and re-press. Layers mounted at BeginPlay are unaffected.

Cause

On macOS the native web view (SAppleWebBrowserWidget, an SViewport subclass) grabs Slate keyboard focus to itself once, on its first Tick after construction ("to keep parity with CEF"). This is engine behavior and bypasses bInteractive = false, which only governs the Slate/UMG layer — SupportsKeyboardFocus() on the native widget is hardcoded true and it is not ours to subclass. The game viewport losing focus runs PlayerController->FlushPressedKeys() (held WASD drop) and shows the cursor. BeginPlay mounts escape it because pawn possession re-focuses the viewport right after; a runtime add has no such re-focus.

Workaround

Don't construct/destroy a display-only ReactWebBrowser at runtime. Mount it once (e.g. at BeginPlay) (its one-time grab is absorbed under possession), then show/hide it with SetVisible — toggling visibility keeps the existing browser alive, so the native grab never re-fires. Tracked under #65.

Slate clip cannot round-corner the CEF layer

  • Platform: all
  • UE version: 5.7
  • Tags: ui, rounded, clip, slate, css

Symptom

Wrapping a ReactWebBrowser in a Retainer Box / Clip to Bounds with a rounded mask does not produce rounded HUD corners — the CEF texture renders square inside the clip.

Cause

CEF texture is composited outside the Slate clip mask.

Workaround

Apply border-radius in HTML/CSS on the root element of your React app. The CEF layer is already transparent by default, so a rounded root naturally produces rounded HUD corners.

SampleProject Live Coding fails

  • Platform: macOS
  • UE version: 5.7
  • Tags: sampleproject, live-coding, content-only, build

Symptom

Live Coding > Compile fails immediately in SampleProject because the project itself is content-only (no Source/ directory of its own).

Workaround

Build the plugin headlessly and relaunch the Editor:

bash
UBT_PATH=/path/to/UnrealBuildTool
"$UBT_PATH" UnrealReactBridge Mac Development -Project="$(pwd)/SampleProject/SampleProject.uproject"
# then restart UnrealEditor

LayerId collision outside a CanvasPanel

  • Platform: macOS
  • UE version: 5.7, 5.8 (cited against 5.8 engine source)
  • Tags: mac, ue57, ue58, layerid, canvaspanel, multi-hud, layout, slate

Symptom

Two ReactWebBrowser widgets share a non-CanvasPanel ancestor (e.g. both are children of the same VerticalBox, Overlay, or Border) and only the first one ever renders. The second stays blank/transparent even though it loads its URL normally and still fires OnReactReady — there's no error, the browser is just never visually registered.

Cause

Slate assigns paint layers per container, and macOS's native web view registers itself keyed on that layer:

  • SPanel::PaintArrangedChildren — the base paint path most panels use (VerticalBox, HorizontalBox, Overlay, Border, …) — hands every child the same LayerId.
  • SConstraintCanvas::OnPaint (what backs UCanvasPanel) is the one exception: it assigns each child its own ChildLayerId = MaxLayerId + 1.
  • FSlateViewportInfo::CreateNativeLayer (SlateRHIRenderer.cpp:364) registers the macOS native web view in a TSet<int32> keyed on that LayerId integer alone.

So two browsers sharing a LayerId register as the same entry in that set and collapse to a single native view — the second is silently dropped. Nesting them under a CanvasPanel instead gives each its own LayerId, and its own native layer.

Workaround

Make every ReactWebBrowser a direct child of a CanvasPanel: create a plain User Widget, drag a Canvas Panel in as its root, and drop the browsers straight onto it. Set that panel's Visibility to Not Hit-Testable (Self Only) so a full-screen HUD container does not swallow the clicks meant for your game.

The plugin also catches this for you: UReactWebBrowser::ValidateCompiledDefaults walks the widget tree at Widget Blueprint compile time and emits a compiler warning naming both colliding browsers and their shared container the moment you compile the Blueprint. The same check reruns at RebuildWidget() for browsers constructed dynamically in C++, which never go through Blueprint compilation. See Multi-HUD at named anchors.

macOS native web view renders at half size

  • Platform: macOS (Retina)
  • UE version: 5.7, 5.8
  • Tags: mac, ue57, ue58, layout, retina, backing-scale, webhud

Symptom

Every ReactWebBrowser paints into the top-left quadrant of its slot and leaves the right/bottom transparent — effectively half size, anchored to the widget's own top-left corner. A browser given a full-width slot only fills the left half; a minimap pinned to the top-right corner of the screen renders shifted well left of where it was placed, because the content shrinks toward the slot's top-left rather than the screen's.

Cause

SAppleWebBrowserWidget::Tick() passes UpdateFrameWithViewport() a size taken from the widget's tick-space geometry, which on macOS is already in points. The PLATFORM_MAC branch then divides it by [NSWindow backingScaleFactor] a second time (ApplePlatformWebBrowser.cpp — UE 5.7 L138-141, UE 5.8 L218-222), so the NSView ends up at half size on a Retina display. The frame origin is not divided, which is why the content anchors to the widget's top-left.

Workaround

None inside the plugin — this is a deliberate decision, not a temporary gap. An earlier version of the plugin compensated for this: it requested the slot at backingScaleFactor times the intended size and pinned it to alignment (0,0), so the engine's redundant division landed back on the size actually asked for. That compensation lived in the old anchor-based HUD layout system (WebHUDAnchorLayout.h) and was deleted along with the rest of that system when the plugin consolidated onto the single UReactWebBrowser widget (see .superpowers/sdd/2026-07-26-react-web-browser/ in the plugin repo for the design rationale) — it was judged unreadable magic (requesting a slot at a size other than the one you actually asked for, purely to cancel out an engine bug two layers down) and not worth carrying forward into a widget meant to be a plain, boring UWidget.

Concretely: on a Retina Mac, every ReactWebBrowser renders at half its assigned size, anchored to its widget's top-left corner, with no workaround inside the plugin. If you need full-size rendering on Retina today, the fix belongs in the engine (ApplePlatformWebBrowser.cpp's redundant backingScaleFactor division), not in application code layered on top of it.

Note this cannot be fixed with UWidget::SetRenderScale() — render transforms live in paint space, while the engine reads tick-space geometry, so they never reach UpdateFrameWithViewport().

macOS web view ignores position-only frame changes

  • Platform: macOS
  • UE version: 5.7, 5.8
  • Tags: mac, ue57, ue58, layout, resize, canvaspanel, webhud

Symptom

A ReactWebBrowser drifts away from its CanvasPanel slot as the window is resized (or as its slot Position is animated/changed some other way), and the drift accumulates the more the position changes without a corresponding size change. A browser whose slot size also tracks the resize looks fine; one pinned with a fixed pixel size and an anchor that only moves the position is the one that goes stale.

Cause

UpdateFrameWithViewport() only commits a recomputed frame when its size differs from the cached one:

cpp
if (bForceRecomputeWindowOnPaint ||
    NewFrame.size.width  != WindowFrame.size.width ||
    NewFrame.size.height != WindowFrame.size.height) { WindowFrame = NewFrame; }
[WebViewWrapper updateframe : WindowFrame ...];

A pure move therefore never reaches the NSView. This is invisible as long as the slot's size keeps changing alongside its position (e.g. a CanvasPanel anchor that stretches with the viewport) — it only surfaces once something holds the size constant while the position keeps moving.

Workaround

None inside the plugin. An earlier version compensated for this by alternating a half-unit nudge on the requested slot size on every relayout (ApplyAppleWebViewFrameNudge() in WebHUDAnchorLayout.h), so the engine's size comparison was never equal and the new origin was always committed. That code lived in the same anchor-based HUD layout system removed when the plugin consolidated onto the single UReactWebBrowser widget — see the note on the half-size entry above for why it wasn't carried forward. If you hit this, the practical mitigation is to keep the browser's slot size changing by at least a fraction of a unit whenever its position changes (e.g. drive both from the same resize/animation callback), so the engine never sees an identical size on a moved frame.

useUnrealState envelope auto-unwrap

  • Platform: all
  • UE version: any
  • Tags: sdk, useUnrealState, envelope, typed-payload

Symptom

Plain window.addEventListener('player:hp', e => …) receives e.detail = { value: 75 }, but useUnrealState('player:hp', 0) returns 75 directly. Mixing the two confuses readers.

Cause

useUnrealState unwraps the typed-payload envelope { value: T } automatically. Raw listeners do not.

Workaround

Prefer useUnrealState for streamed scalar values; reserve raw listeners for events whose payload is not a {value} envelope (e.g. PushMap, PushRaw).

Released under the MIT License.