Docs / For developers

Patches

Every patch and game setting FramePort knows: 155 entries in 5 groups. A game's recipe is its chosen patches and settings; tested games get theirs from the catalog (GAMES.md), and other games get the patches FramePort suggests from its analysis. You change them on the game page under Customize.

Each entry says what the patch does, whether it changes the APK or only the install, when FramePort suggests it, its options, the catalog games whose recipe names it and the launch-test signatures that suggest it. Patches that are on by default are on for every game, so the catalog rarely names them.

Link to an entry with its id, dots replaced by dashes: PATCHES.md#frame-unity_text_input for frame.unity_text_input.

#Groups

#Index

PatchIdGroupCatalog games
AC Nexus: no AppSW at 72 Hzpatch_ac_nexus_no_appsw_72Patches from OVRPort
AC Nexus: no AppSW at 90 Hzpatch_ac_nexus_no_appsw_90Patches from OVRPort1
Clean up Frida leftovers in smalipatch_clean_up_fridaPatches from OVRPortdefault
Copy OVRPort librariespatch_copy_librariesPatches from OVRPortdefault
Copy OVRPlugin if VrApi is presentpatch_copy_ovrplugin_vrapiPatches from OVRPortdefault
Disable controller tracking offsetpatch_disable_controller_offsetPatches from OVRPort
Disable Meta XR Audio telemetrypatch_disable_meta_xr_audio_telemetryPatches from OVRPort
Disable application space warp if usedpatch_disable_space_warpPatches from OVRPort3
Fix minimal Android SDKpatch_fix_min_android_sdkPatches from OVRPortdefault
Fix UE4 crash with Unity stubpatch_fix_unreal_crashPatches from OVRPortdefault
Force enable passthroughpatch_force_passthroughPatches from OVRPort2
Generate OVRPort configpatch_generate_configPatches from OVRPortdefault
Fix launcher icon entrypatch_launcher_entryPatches from OVRPortdefault
Mark application to allow backuppatch_mark_allow_backupPatches from OVRPortdefault
Mark application as debuggablepatch_mark_as_debuggablePatches from OVRPortdefault
Patch Meta XR Audiopatch_meta_xr_audioPatches from OVRPortdefault
Patch Oculus detection for Unitypatch_oculus_unityPatches from OVRPortdefault
Patch Oculus detection for Unrealpatch_oculus_unrealPatches from OVRPortdefault
Remove localized app namespatch_remove_localized_namesPatches from OVRPortdefault
Remove Unreal's ForceQuitpatch_remove_unreal_force_quitPatches from OVRPort29
Remove uses-librarypatch_remove_uses_libraryPatches from OVRPortdefault
Remove VrApi librarypatch_remove_vrapiPatches from OVRPort
Replace application label and iconpatch_replace_icon_labelPatches from OVRPortdefault
Pico/YVR/Quest metadatapatch_vr_metadataPatches from OVRPortdefault
VrApi → OpenXR adapter (OVRPort)patch_vrapi_openxrPatches from OVRPort
FrameBridge OpenXR adapterframe.adapterSteam Frame patchesdefault
Content files from the game's dataframe.asset_filesSteam Frame patches1
Skip Meta avatarsframe.avatar_stubSteam Frame patches1
BlazeRush: controllers without Meta avatars, own shader cacheframe.blazerushSteam Frame patches1
OpenGL ES: multiview shaders on flat panels (HUD, menus)frame.gl_multiview_fboSteam Frame patches1
GL shim (Mesa GLSL compatibility)frame.gl_shimSteam Frame patches2
Godot apps: start without a clipboard serviceframe.godot_clipboardSteam Frame patches
Hardware video decoding (H.264, HEVC, VP9)frame.hw_video_decodeSteam Frame patches2
Language packs from the game's filesframe.langpacksSteam Frame patches
Launcher category (INFO → LAUNCHER)frame.launcherSteam Frame patchesdefault
GL wrapper: OpenGL ES depth formats (Minecraft)frame.ltw_depthSteam Frame patchesdefault
Declare Meta-only permissionsframe.meta_permissionsSteam Frame patches1
Meta XR Audio: skip Quest telemetry classframe.metaxr_telemetrySteam Frame patchesdefault
Clear android:debuggableframe.nodebugSteam Frame patches3
Oculus OS telemetry class stubsframe.oculusosSteam Frame patches13
Fix crash when the game prepares the microphoneframe.ovr_microphoneSteam Frame patches
Trace Meta platform requests (diagnostics)frame.ovr_traceSteam Frame patches
Platform compat (ovrMessageType_ToString)frame.ovrplatformcompatSteam Frame patchesdefault
Stub missing Meta platform functionsframe.ovrstubsSteam Frame patchesdefault
Unpaired pointer-authentication checksframe.pac_hintsSteam Frame patches1
SDL apps: start without a clipboard serviceframe.sdl_clipboardSteam Frame patches3
Stress Level Zero: let Unity start Vulkan itselfframe.slz_vulkan_hooksSteam Frame patches1
Start straight in VR (skip the 2D launcher)frame.start_activitySteam Frame patches
Allow swapchains larger than 4096 pxframe.swapchain_limitSteam Frame patchesdefault
Team Beef ports: treat the Frame as a Meta headsetframe.tbxr_vendorSteam Frame patches1
GL shim for Unity (no multisampled render-to-texture)frame.unity_gl_shimSteam Frame patches10
Unity: render each eye separately (no multiview)frame.unity_multipassSteam Frame patches1
Unity: disable MSAAframe.unity_no_msaaSteam Frame patches6
Unity: skip OVROverlay layers (fades, splash screens)frame.unity_no_overlay_copySteam Frame patches2
Unity: start VR without Meta's system appsframe.unity_oculus_checkSteam Frame patches8
Unity: keep MSAA off at runtime (OVRManager)frame.unity_runtime_msaa_offSteam Frame patches15
Make Unity text fields workframe.unity_text_inputSteam Frame patches55
Unity: headset always counts as wornframe.unity_user_presenceSteam Frame patches1
GL shim for Unreal (no multisampled render-to-texture)frame.unreal_gl_shimSteam Frame patches1
Unreal: stand-ins for OVRPlugin functions OVRPort lacksframe.unreal_ovrp_entrypointsSteam Frame patches1
Unreal: Quest controller bindings (RPOC key map)frame.unreal_quest_keymapSteam Frame patches3
Unreal: don't wait for the Quest shader precompileframe.unreal_quest_precompileSteam Frame patches3
Unreal: start without the OBB checkframe.unreal_skip_obb_checkSteam Frame patches
Unreal: thumb follows the capacitive touchesframe.unreal_thumb_touchSteam Frame patches7
Vivox voice chat: skip Android 12 audio routingframe.vivox_audio_routeSteam Frame patches
Vulkan: drop invalid render-pass pointersframe.vk_sanitizeSteam Frame patchesdefault · 1
VrApi → OpenXR bridgeframe.vrapi_bridgeSteam Frame patches3
Quiet Meta's VrApi loader (OpenXR games)frame.vrapi_stubSteam Frame patches2
OpenGL ES: shader fixes (Vulkan layer under Zink)frame.zink_shader_fixSteam Frame patches1
Pointer startadapter.aim_forwardGame settings
Pointer angleadapter.aim_pitchGame settings
Pointer turnadapter.aim_yawGame settings
Use controllersadapter.controller_fixGame settings1
Show Steam Frame controllersadapter.controller_modelsGame settings3
Stand in for cube layersadapter.cube_standinGame settings
Show curved menus and screensadapter.cylinder_stripsGame settings
Show 360° backgrounds and videosadapter.equirect_emulGame settings4
360° detailadapter.equirect_faceGame settings
360° picture orientationadapter.equirect_flipGame settings
360° video frame rate limitadapter.equirect_fpsGame settings
360° sharpnessadapter.equirect_resGame settings
360° 3Dadapter.equirect_stereoGame settings
Per-eye diagnostics (log)adapter.eye_debugGame settings
Fix upside-down menusadapter.flip_emulGame settings
Rotate panels 180°adapter.flip_quadsGame settings
Don't pause on short interruptionsadapter.focus_holdGame settings4
Ignore focus dips up toadapter.focus_hold_msGame settings2
Hide Quest foveationadapter.foveation_fixGame settings
Hide fast anti-aliasing (OpenGL ES)adapter.gl_hide_msrttGame settings1
Draw each eye separately (OpenGL ES)adapter.gl_hide_multiviewGame settings1
GL shim: high-precision vertex shadersadapter.gl_highp_markersGame settings1
GL shim: integer vertex inputsadapter.gl_int_attribsGame settings1
Flat panel diagnostics (log)adapter.gl_mv_debugGame settings
Fix freezes when controllers vibrateadapter.haptic_fixGame settings39
Vibration strengthadapter.haptic_scaleGame settings
Turn off space warpadapter.hide_space_warpGame settings4
Controller input diagnostics (log)adapter.input_diagGame settings
Extra diagnostics (log)adapter.layer_debugGame settings
Drop broken layersadapter.layer_fixGame settings
Vulkan format workaroundadapter.mutable_fixGame settings
Unity frame loop: wait for skipped framesadapter.ovrp_begin_gateGame settings1
Steadier hands (older Unity)adapter.ovrp_hold_physicsGame settings1
See your roomadapter.passthrough_emulGame settings
Steadier head trackingadapter.pose_consistencyGame settings1
Pose timing diagnostics (log)adapter.pose_debugGame settings
Fix hands lagging behind controllersadapter.pose_time_fixGame settings8
Treat newer Quest controllers as Touchadapter.profile_remapGame settings
Animate fingers from touchadapter.proximity_emulGame settings
Keep pictures in boundsadapter.rect_clampGame settings
Refresh rateadapter.refresh_rateGame settings2
Wait for the game's GPUadapter.release_waitGame settings
Re-create play spaceadapter.respace_kickGame settings
Sharpnessadapter.scaleGame settings4
Room depthadapter.scene_depthGame settings
Pretend room layoutadapter.scene_emulGame settings1
Room heightadapter.scene_heightGame settings
Room widthadapter.scene_widthGame settings
Eye-image snapshots (diagnostics)adapter.snapshotGame settings
Keep menus in placeadapter.stable_localGame settings1
Drop layer color fadesadapter.strip_color_biasGame settings
Strip depth layersadapter.strip_depthGame settings
Show video panelsadapter.surface_emulGame settings
Native video surfaces (Batman renderer)adapter.surface_nativeGame settings1
Swap eyesadapter.swap_eyesGame settings
Retry refused picture formatsadapter.swapchain_fixGame settings
Steady controller input after focusadapter.sync_guardGame settings2
Hide Vulkan foveationadapter.vk_hide_fdmGame settings1
Stop objects popping in and outadapter.vk_query_slotsGame settings
Vulkan shader dump (diagnostics)adapter.vk_shader_dumpGame settings
Vulkan shader fixesadapter.vk_shader_fixGame settings1
Fix depth flicker (Unreal Vulkan)adapter.vk_spec_fixesGame settings2
Vulkan error checks (log)adapter.vk_validationGame settings
OpenGL ES shader dump (diagnostics)adapter.zink_shader_dumpGame settings
OpenGL ES shader fixesadapter.zink_shader_fixGame settings1
Keep the game's saved resolution in stepdevice.config_syncFiles and settings on the Frame1
Show as VR or as a flat windowdevice.display_modeFiles and settings on the Frame
Settings files for the gamedevice.filesFiles and settings on the Frame2
Eye-tracked foveation (Valve)device.foveationFiles and settings on the Frame
Hide Android's navigation bardevice.hide_navbarFiles and settings on the Frame
Extra Lepton settingsdevice.lepton_envFiles and settings on the Frame3
Controllers as a gamepad (Steam Input)device.steam_gamepadFiles and settings on the Frame
Show the app's Android window (for typing)device.text_input_windowFiles and settings on the Frame55
Launch options (SteamVR or OpenXR)pcvr.launch_argsPC VR (Proton and Revive)2
Provide the Oculus runtime from Revive (Frame)pcvr.libovr_redirectPC VR (Proton and Revive)
No Unreal crash reporterpcvr.no_crash_reporterPC VR (Proton and Revive)
Patch Oculus detection for Unreal (Frame)pcvr.oculus_unrealPC VR (Proton and Revive)
Extra Proton settings (Frame)pcvr.proton_envPC VR (Proton and Revive)
Proton debug log (Frame)pcvr.proton_logPC VR (Proton and Revive)
Proton version (Frame)pcvr.proton_toolPC VR (Proton and Revive)
Use the repack's launcher (bundled Revive)pcvr.repack_launcherPC VR (Proton and Revive)
Revive (Oculus LibOVR → OpenXR)pcvr.revivePC VR (Proton and Revive)
Revive: SteamVR (OpenVR) backend on PCpcvr.revive_openvrPC VR (Proton and Revive)
Automatic SteamVR performance settings (this PC)pcvr.steamvr_tuningPC VR (Proton and Revive)4
SteamVR overlay app (Frame)pcvr.vr_overlayPC VR (Proton and Revive)
Frame OpenXR compatibility layerpcvr.xr_timefixPC VR (Proton and Revive)5

#Patches from OVRPort

OVRPort converts a Quest game's Meta VR code to standard OpenXR; FramePort picks which of its patches run. The list comes from the OVRPort CLI at runtime (new OVRPort patches appear in the app on their own); this page shows FramePort's bundled list (patches/overport.py).

#AC Nexus: no AppSW at 72 Hz

Assassin's Creed Nexus: smoother picture at 72 Hz (turns off Meta's frame-rate trick).

  • patch_ac_nexus_no_appsw_72
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Only for its game's build: outside it the whole OVRPort run fails, so recipes only use it where it applies.
  • Conflicts with: patch_ac_nexus_no_appsw_90
  • Source: patches/overport.py

Assassin's Creed Nexus (build 207706 only): turns off application space warp and runs at 72 Hz.

#AC Nexus: no AppSW at 90 Hz

Assassin's Creed Nexus: smoother picture at 90 Hz (turns off Meta's frame-rate trick).

  • patch_ac_nexus_no_appsw_90
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested (on): This Assassin's Creed Nexus build runs smoothly on the Frame without application space warp, at 90 Hz.
  • Only for its game's build: outside it the whole OVRPort run fails, so recipes only use it where it applies.
  • Conflicts with: patch_ac_nexus_no_appsw_72
  • Catalog games (1): Assassin's Creed Nexus.
  • Source: patches/overport.py

Assassin's Creed Nexus (build 207706 only): turns off application space warp and runs at 90 Hz.

#Clean up Frida leftovers in smali

Removes debugging leftovers some game files contain.

Removes leftovers from dumped/modded APKs.

#Copy OVRPort libraries

Adds the parts that let a Quest game run on the Steam Frame. Needed for every Quest game.

Adds OVRPort's OpenXR loader dispatcher and platform loader. Required: without it nothing is translated.

#Copy OVRPlugin if VrApi is present

Gives older Quest games a newer version of Meta's VR plugin that can be converted.

Swaps in an OpenXR OVRPlugin for games that use VrApi through OVRPlugin (older Unity/Unreal).

#Disable controller tracking offset

Removes a controller position adjustment, for games whose hands look misplaced.

Removes OVRPort's controller pose offset if controllers look misplaced.

#Disable Meta XR Audio telemetry

Stops Meta's audio library from reporting to Meta (only matters on PC emulators).

Skips Meta XR Audio's telemetry under x86_64 ARM translation (emulators). Not needed on the Frame, which runs games natively.

#Disable application space warp if used

Turns off Meta's frame-rate trick, which causes glitches or hangs outside Quest headsets.

  • patch_disable_space_warp
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested (on): Very heavy game (… GiB) using OVRPlugin: application space warp causes artifacts/hangs off-Quest.
  • Offered (off): Enable if the game shows warping artifacts or hangs (uses OVRPlugin space warp).
  • Catalog games (3): Asgard's Wrath 2, Batman: Arkham Shadow, Marvel's Deadpool VR.
  • Source: patches/overport.py

For heavy games that use application space warp: it causes artifacts or hangs on non-Quest runtimes (for example Asgard's Wrath 2, Batman: Arkham Shadow).

#Fix minimal Android SDK

Raises the minimum Android version the game declares, so the new parts load.

Raises minSdk where the loader needs it.

#Fix UE4 crash with Unity stub

Prevents a start-up crash in some Unreal games.

Works around a UE4 startup crash.

#Force enable passthrough

Lets mixed-reality games start even though they insist on a camera view of your room.

  • patch_force_passthrough
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested (on): Mixed-reality-only game (passthrough required, no guardian): force passthrough on.
  • Catalog games (2): BAM, Demeter.
  • Suggested by launch-test signatures:
    • passthrough-missing (error): The game needs Meta passthrough (the camera view), which the Frame lacks; the adapter emulates it.
  • Source: patches/overport.py

For mixed-reality-only games. On the Frame, passthrough is emulated by the FrameBridge adapter (grayscale cameras).

#Generate OVRPort config

Writes the conversion's settings into the game.

Writes liboverport.config.so with runtime options.

#Fix launcher icon entry

Makes sure the game has an entry that can be started.

Adds a launcher entry point (Lepton additionally needs category LAUNCHER, see the Frame 'launcher' fix).

#Mark application to allow backup

Allows the game's data to be backed up.

Allows data backup.

#Mark application as debuggable

Allows reading the game's logs, which helps find problems.

Lets you read logs/attach. Some Unreal games abort under CheckJNI when debuggable; the Frame 'nodebug' fix undoes it.

#Patch Meta XR Audio

Makes Meta's 3D audio library work outside Quest headsets.

Neutralises Meta XR Audio's Quest-only calls (Unity/Wwise).

#Patch Oculus detection for Unity

Lets Unity games accept a headset that isn't a Quest.

Makes Unity's Oculus checks pass on other runtimes.

#Patch Oculus detection for Unreal

Lets Unreal games accept a headset that isn't a Quest.

Makes Unreal's Oculus checks pass on other runtimes.

#Remove localized app names

Keeps one name for the game, so it shows the same everywhere.

Keeps one label so the title is stable.

#Remove Unreal's ForceQuit

Stops some Unreal games from closing themselves right after starting.

  • patch_remove_unreal_force_quit
  • Changes: Changes the APK (during the OVRPort conversion).
  • Offered (off): Built as the alternate APK for Unreal games (use it if the game quits itself).
  • Catalog games (29): Asgard's Wrath 2, BARTENDER VR SIMULATOR, Carve Snowboarding, Creed, Espire 1: VR Operative (Quest Edition), Espire 2, ExploreVR, In Death: Unchained and 21 more.
  • Suggested by launch-test signatures:
    • force-quit (error): The game quit itself right after starting.
  • Source: patches/overport.py

For Unreal games that close themselves right after starting (for example Phantom: Covert Ops). Also disables the in-game Quit.

#Remove uses-library

Removes requirements for Quest-only system parts.

Drops Quest-only shared library requirements.

#Remove VrApi library

Removes Meta's old VR library when the game doesn't need it.

  • patch_remove_vrapi
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Source: patches/overport.py

Not recommended: breaks games that load VrApi through OVRPlugin.

#Replace application label and icon

Uses the store's name and icon for the game.

Uses the store title/icon (OVRPort image service) for the app label.

#Pico/YVR/Quest metadata

Marks the game as a VR app so headsets show it as one.

Adds the VR app metadata other launchers expect.

#VrApi → OpenXR adapter (OVRPort)

OVRPort's own converter for games that use Meta's oldest VR interface (experimental).

  • patch_vrapi_openxr
  • Changes: Changes the APK (during the OVRPort conversion).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Only for its game's build: outside it the whole OVRPort run fails, so recipes only use it where it applies.
  • Conflicts with: frame.vrapi_bridge, patch_remove_vrapi
  • Source: patches/overport.py

OVRPort's own VrApi→OpenXR adapter for engines that call libvrapi.so directly: the same upstream code as FramePort's 'VrApi → OpenXR bridge' without its Frame-specific changes. Only in OVRPort's experimental CLI builds (the stable CLI lists it but can't apply it).

#Steam Frame patches

FramePort's own changes to a converted Quest game, for what the Steam Frame lacks or does differently.

#FrameBridge OpenXR adapter

FramePort's layer between the game and the Steam Frame: fills in what the Frame lacks (controllers, room, passthrough). Needed for every converted game.

  • frame.adapter · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Required for every OpenXR/overport build on the Frame.
  • Suggested by launch-test signatures:
    • cube-swapchain-refused (fatal): The game asked for a cube-map swapchain (for example an OVROverlay skybox or loading cube), which the Frame's runtime doesn't have.
    • graphics-requirements-missing (fatal): The game can't start VR on the Frame; rebuild it with the current FramePort.
    • swapchain-rect-invalid (fatal): The runtime rejects the game's frames, so it stops drawing (for example stuck at a "Waiting" box).
    • time-conversion (warning): The Frame's runtime lacks timespec time conversion; the current adapter build emulates it.
  • Source: patches/frame/adapter.py

Wraps OVRPort's generic OpenXR loader (renamed libopenxr_loader_original.so). Fixes the Frame runtime's gaps: retries rejected GLES swapchain formats/MSAA (Frame takes sRGB only), drops unsupported instance extensions and layers, emulates XR_FB_passthrough (ALPHA_BLEND), Meta scene/spatial entities (guardian-sized room), XR_KHR_convert_timespec_time, and vertically flipped quad layers; maps Frame controllers to Touch; optionally serves Steam Frame controller models (XR_FB_render_model). Its settings are under Game settings.

#Content files from the game's data

Lets the game find extra content it keeps next to its data (for example Star Wars Tales' seasons).

  • frame.asset_files
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): The game asks Meta's platform for asset files and its data has … content file(s) (*.pak) that OVRPort's loader doesn't report.
  • Catalog games (1): Star Wars: Tales from the Galaxy's Edge.
  • Source: patches/frame/langpack.py

Some games keep content in separate files next to their OBB (for example Star Wars: Tales from the Galaxy's Edge: its seasons and sound banks) and ask Meta's platform for them as asset files. OVRPort's platform loader doesn't know them, so the game waits for content that never arrives (black screen after loading). Lists the content files shipped with the game's data (*.pak) as installed and answers their download request at once with the file's path; nothing is copied or downloaded. Shares the language-pack library.

#Skip Meta avatars

Lets games start that would stop at Meta's avatars (for example BlazeRush). No Meta avatars.

  • frame.avatar_stub
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (1): BlazeRush.
  • Suggested by launch-test signatures:
    • avatar-driver-missing (fatal): Meta's avatar library stopped the game because it needs Meta's Horizon app.
  • Source: patches/frame/avatar_stub.py

Meta's avatar library needs Meta's Horizon app, which the Frame doesn't have; it then stops the game at start ("Failed to launch SystemActivities", for example BlazeRush). Replaces it with a library that does nothing, so the game runs without Meta avatars.

#BlazeRush: controllers without Meta avatars, own shader cache

Makes BlazeRush's menus and controllers work without Meta's avatars, and lets its shader fixes take effect.

  • frame.blazerush
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Only for its game's build: outside it the whole OVRPort run fails, so recipes only use it where it applies.
  • Catalog games (1): BlazeRush.
  • Source: patches/frame/blazerush.py

BlazeRush 1.0.349 only (Klownicle's guide, GitHub #57). Its menus wait for Meta's avatar, which never comes on the Frame, before they create the game's own controllers: the second menu ignored all input. Two instructions in libtargemapp.so skip that wait and the avatar mesh drawing; the game's shader cache gets a new folder name (cache/br_shader_v1), so programs compiled before the GL shim's shader fixes aren't reused. Only this exact build is changed (code fingerprint and every instruction checked); anything else is left as it is.

#OpenGL ES: multiview shaders on flat panels (HUD, menus)

Experimental: shows HUDs, menus and other flat panels that stay black on the Frame (for example Doom3Quest's HUD and PDA).

  • frame.gl_multiview_fbo · experimental
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Offered (off): Own OpenGL ES engine with multiview shaders: turn on if HUD, menu or other flat panels stay black on the Frame (for example Doom3Quest's HUD and PDA).
  • Catalog games (1): Doom3Quest.
  • Source: patches/frame/gl_multiview_fbo.py

Some OpenGL ES engines compile every shader for multiview (both eyes in one draw, num_views=2) and use the same shaders to draw into ordinary single-layer framebuffers, for example a HUD or PDA screen rendered to a texture. Quest's driver draws them anyway; the Frame's driver (Mesa) follows the OVR_multiview rule and silently drops every such draw, so those panels stay black (for example Doom3Quest's HUD and PDA). Loads OpenGL ES through a small interposer (libfpglmv.so) that draws those cases with a single-view copy of the shader program (left-eye view; uniforms copied before each such draw). Eye-buffer draws are unchanged. Logs under the tag GLMV; the setting gl_mv_debug adds error checks and counters.

#GL shim (Mesa GLSL compatibility)

Corrects graphics code the Frame's drivers reject (black screen with sound).

  • frame.gl_shim · experimental
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): GLES engine resolving GL through eglGetProcAddress (GLAD) on the VrApi bridge.
  • Requires: frame.vrapi_bridge
  • Catalog games (2): BlazeRush, Path of the Warrior.
  • Suggested by launch-test signatures:
    • gl-shader-failed (error): The game's shaders don't compile on the Frame, so parts of the picture are missing.
  • Source: patches/frame/vrapi_bridge.py

Loads libglshim.so ahead of libEGL in every engine library that fetches GL through eglGetProcAddress. Fixes Quest-only leniency that Mesa/Zink rejects: #pragma before #extension, implicit int/float conversions (enables GL_EXT_shader_implicit_conversions), and multiview shaders used on single-view framebuffers (hides GL_OVR_multiview; gl_hide_multiview=0 turns that off). Logs every failed shader with its source lines (logcat tag GLShim). Symptom: black screen with working audio in a GLES game.

#Godot apps: start without a clipboard service

Lets Godot games start on the Frame (they'd crash looking for a clipboard).

  • frame.godot_clipboard · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Godot 4 app: it crashes at start in Lepton, which has no clipboard service.
  • Suggested by launch-test signatures:
    • godot-no-clipboard (fatal): The app crashed at start because the Frame's Android has no clipboard.
  • Source: patches/frame/godot_clipboard.py

Lepton's Android has no clipboard service, and the Android code of Godot 4.2-4.4 (for example EndoparasiticVR) casts the missing service to a ClipboardManager without checking, so the app crashes at start with a NullPointerException in Godot.<init>. That check is skipped and Godot's clipboard functions do nothing instead (an in-place edit of classes.dex).

#Hardware video decoding (H.264, HEVC, VP9)

Plays the game's videos on the Frame's video hardware, so 4K and 8K video runs smoothly.

  • frame.hw_video_decode · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested (on): The game plays video through Android's decoders (MediaCodec, ExoPlayer or VLC): decode it on the Frame's hardware.
  • Catalog games (2): 4XVR Video Player, Batman: Arkham Shadow.
  • Source: patches/frame/hw_video_decode.py

Decodes the game's videos on the Frame's hardware video decoder instead of Android's software decoders, which stutter or fall behind with 4K/8K video (for example video players, Batman: Arkham Shadow's cutscenes). Adds FramePort's codec plugin (OMX.frameport.avc/hevc/vp9.decoder) to this game's container only; the APK isn't changed. When the hardware is busy (for example Steam's own hardware video decoding is on) the video is decoded in software as before.

#Language packs from the game's files

Lets the game use language files already in its data instead of waiting for a download that never comes.

  • frame.langpacks · experimental
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Source: patches/frame/langpack.py

OVRPort's platform loader answers the Meta Platform SDK's language-pack calls (ovr_LanguagePack_GetCurrent/SetCurrent) with 'no request', so a game that asks for its language pack never gets an answer. Adds a small library that serves language packs (<tag>.lang, for example de.lang) found in the game's own data folders (OBB and app files) through the same calls, the asset-file list and the status call, without any download. The game then finds the file path itself. The pack it applies with SetCurrent wins; otherwise the environment variable FRAMEPORT_LANGPACK (a tag), otherwise the only pack there is. Everything else goes to the loader unchanged. Off by default: turn it on for a game whose data has such files (the game page lists the patch only then).

#Launcher category (INFO → LAUNCHER)

Makes the game start from the Frame's Steam library.

  • frame.launcher · on by default · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Manifest uses category INFO only; Lepton needs LAUNCHER.
  • Suggested (on): Applied automatically if the manifest needs it.
  • Suggested by launch-test signatures:
    • no-launcher (fatal): Nothing starts: Lepton found no entry point in the app (an activity with category LAUNCHER).
  • Source: patches/frame/manifest_fixes.py

Lepton only launches an activity with category LAUNCHER (Quest apps often use INFO). Symptom when missing: launch.log says 'APP_ACTIVITY is empty' and nothing starts.

#GL wrapper: OpenGL ES depth formats (Minecraft)

Stops a black picture in Minecraft launchers (for example QuestCraft).

  • frame.ltw_depth · on by default · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Ships LTW (Minecraft's OpenGL-to-OpenGL ES wrapper): Minecraft's 32-bit depth textures need the OpenGL ES format on the Frame (for example QuestCraft).
  • Source: patches/frame/ltw_depth.py

Minecraft asks for desktop OpenGL's GL_DEPTH_COMPONENT32 depth textures. Some builds of LTW, the OpenGL-to-OpenGL ES wrapper in Minecraft launchers such as QuestCraft, pass that on unchanged; Quest's driver accepts it, the Frame's Mesa rejects it (GL_INVALID_OPERATION in glTexImage2D), so the depth buffer never exists and the picture stays black. LTW then loads OpenGL ES through a small shim that asks for GL_DEPTH_COMPONENT32F (or 24-bit) instead.

#Declare Meta-only permissions

Declares Meta's permissions some mixed-reality games ask for, so they don't stop.

  • frame.meta_permissions
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Mixed-reality game that needs the room model: its 'use spatial data' permission must be granted (for example Demeter).
  • Catalog games (1): Demeter.
  • Source: patches/frame/manifest_fixes.py

Declares com.oculus.permission.* / horizonos.permission.* that the app uses, so Android grants them at install (for example the 'use spatial data' permission of mixed-reality games like Demeter).

#Meta XR Audio: skip Quest telemetry class

Skips a Quest-only reporting step in Meta's audio library that crashes some games.

  • frame.metaxr_telemetry · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Meta XR Audio present; patched automatically if it has the telemetry lookup.
  • Suggested by launch-test signatures:
    • oculus-os-class (fatal): The game looks up a Quest-only system class and aborts.
  • Source: patches/frame/telemetry.py

Unreal builds of Meta XR Audio abort ('ClassNotFoundException com.oculus.os.AnalyticsEvent') on non-Quest devices. Patches that one JNI FindClass call so the library continues (for example NOPE Challenge).

#Clear android:debuggable

Stops strict debugging checks that make some games quit.

  • frame.nodebug · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unreal Engine ….…: older UE4 makes JNI calls CheckJNI rejects (for example Time Stall aborted on GetStringUTFChars(NULL)).
  • Suggested (on): Unreal build of Meta XR Audio: its telemetry lookup leaves a pending JNI exception that CheckJNI turns into an abort (for example NOPE Challenge).
  • Offered (off): Enable if the game aborts with 'JNI DETECTED ERROR' (CheckJNI).
  • Catalog games (3): ExploreVR, NOPE CHALLENGE, Time Stall.
  • Suggested by launch-test signatures:
    • checkjni-abort (fatal): Android's debug checks stopped the game.
  • Source: patches/frame/manifest_fixes.py

OVRPort marks apps debuggable; that turns on CheckJNI, which aborts some Unreal games on sloppy JNI calls ('JNI DETECTED ERROR', for example 'GetStringUTFChars ... NULL' in Time Stall). Clear it for those.

#Oculus OS telemetry class stubs

Provides stand-ins for Quest system calls some games make at start.

  • frame.oculusos
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): The Unreal build of Meta XR Audio looks up com.oculus.os.AnalyticsEvent and aborts without it (for example NOPE Challenge).
  • Suggested (on): Several Meta SDK libraries look up com.oculus.os.AnalyticsEvent (…); games like this abort without the stub (for example Nano).
  • Offered (off): … references com.oculus.os.AnalyticsEvent; usually harmless (for example Batman: Arkham Shadow and LEGO Bricktales run without it). Enable if the game aborts with ClassNotFoundException.
  • Catalog games (13): AgeOfJoy, AllInOneSports, Caves, Deep Cuts, Does it Stack?, Nano, NOPE CHALLENGE, RC Pilot Trainer and 5 more.
  • Suggested by launch-test signatures:
    • oculus-os-class (fatal): The game looks up a Quest-only system class and aborts.
  • Source: patches/frame/telemetry.py

Adds no-op com.oculus.os.AnalyticsEvent / UnifiedTelemetryLogger classes for native code that looks them up through the app class loader (for example Nano, NOPE Challenge).

#Fix crash when the game prepares the microphone

Stops a crash a few seconds after the logo in games with voice chat.

  • frame.ovr_microphone
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): The game uses Meta's microphone API (ovr_Microphone_GetOutputBufferMaxSize), which crashes in OVRPort's library before the microphone is started.
  • Suggested by launch-test signatures:
    • ovr-microphone-crash (fatal): The game crashed while setting up the microphone (for example Unreal's Oculus voice chat a few seconds after the logo).
  • Source: patches/frame/ovr_microphone.py

OVRPort's Meta platform library opens the microphone only when it's started, but answers a game's question about the microphone buffer size from that not-yet-opened stream: games that ask first (Unreal's Oculus voice chat, for example The Walking Dead: Saints & Sinners Ch. 2) crash a few seconds after the logo (SIGSEGV in libaaudio.so). Adds the missing check (size 0 until the microphone is started).

#Trace Meta platform requests (diagnostics)

For troubleshooting: records the game's requests to Meta's online services.

  • frame.ovr_trace · experimental · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Source: patches/frame/ovr_trace.py

Logs every Meta Platform SDK request the game makes (user, entitlement, cloud saves, ...) and the messages that answer them, and every 10 s the requests that never got an answer (logcat tag fp_ovrtrace, in launch.log). For games that wait forever on a loading screen (for example Vader Immortal after its intro). Changes nothing: every call goes to the real function.

#Platform compat (ovrMessageType_ToString)

Adds a small piece of Meta's platform library that some games need to start.

  • frame.ovrplatformcompat · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Applied automatically when the OVRPort build needs it.
  • Suggested by launch-test signatures:
    • missing-ovr-symbol (fatal): The game can't load because OVRPort's platform loader lacks Meta platform functions it uses.
  • Source: patches/frame/platform_libs.py

Adds a real ovrMessageType_ToString (OVRPort's platform compat library) for games whose platform loader lacks it (for example The Climb 2). OVRPort 1.2.5+ adds the same library itself; then this is skipped.

#Stub missing Meta platform functions

Provides stand-ins for Meta store functions the game expects, so it doesn't crash at start.

  • frame.ovrstubs · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Applied automatically when the OVRPort build needs it.
  • Suggested by launch-test signatures:
    • missing-ovr-symbol (fatal): The game can't load because OVRPort's platform loader lacks Meta platform functions it uses.
  • Source: patches/frame/platform_libs.py

Generates no-op stubs for ovr_* functions the game imports but OVRPort's platform loader lacks (for example Espire 1/2, Wallace & Gromit, The Climb 2). Symptom: UnsatisfiedLinkError / 'cannot locate symbol ovr_...'. Online/store features stay unavailable.

#Unpaired pointer-authentication checks

Stops a crash on the Frame's processor in games whose code the Quest runs more leniently (for example Star Wars Pinball VR).

  • frame.pac_hints
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (1): Star Wars Pinball VR.
  • Suggested by launch-test signatures:
    • pac-unpaired (fatal): The game crashed on a CPU check the Quest ignores but the Frame enforces.
  • Source: patches/frame/pac_hints.py

Some engines contain assembly (for example OpenSSL's) that checks a return-address signature it never made. The Quest's CPU ignores those checks, the Steam Frame's enforces them: the game crashes with SIGILL as soon as it uses that code, for example on its first network connection (Star Wars Pinball VR). In a library with unpaired checks, the signing and checking instructions become no-ops.

#SDL apps: start without a clipboard service

Lets SDL and LÖVE games start on the Frame (they'd crash looking for a clipboard).

  • frame.sdl_clipboard · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): SDL app: it crashes at start in Lepton, which has no clipboard service.
  • Catalog games (3): Time Crisis II VR (Test), Time Crisis VR (Experimental), WiiCompiled VR.
  • Suggested by launch-test signatures:
    • sdl-no-clipboard (fatal): The app crashed at start because the Frame's Android has no clipboard.
  • Source: patches/frame/sdl_clipboard.py

Lepton's Android has no clipboard service, and SDL's Java code (SDL2 and LÖVE games, for example Dramatic Shape) registers a clipboard listener at start without checking, so the app crashes with a NullPointerException in SDLClipboardHandler. That call is skipped (an in-place edit of classes.dex).

#Stress Level Zero: let Unity start Vulkan itself

Stops a start-up crash in Stress Level Zero games (for example BONELAB).

  • frame.slz_vulkan_hooks
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Stress Level Zero's graphics plugin crashes Unity's Vulkan start-up on the Frame (for example BONELAB 1.2974).
  • Catalog games (1): BONELAB.
  • Suggested by launch-test signatures:
    • slz-vulkan-hook-crash (fatal): The game's own graphics plugin crashes or hangs it before the first frame (for example BONELAB 1.2974).
  • Source: patches/frame/slz_vulkan_hooks.py

Stress Level Zero's graphics plugin (libSLZQuestNative.so, for example BONELAB 1.2974) hooks Unity's Vulkan start-up and its texture samplers. On the Frame the hook calls an invalid function while Vulkan starts, and the game crashes or hangs before the first frame. The plugin's two hooks are switched off, so Unity starts Vulkan itself. Its pipeline cache isn't used: the first start spends about half a minute prewarming shaders.

#Start straight in VR (skip the 2D launcher)

Opens the app straight in VR, skipping its flat launcher screen. Turn off to use the launcher, for example to import new content.

  • frame.start_activity · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Offered (off): The app opens a 2D launcher; its VR part is …. Turn on to start that directly once the app is set up.
  • Options: activity: str, default empty — Activity to start (empty: the app's VR activity)
  • Source: patches/frame/manifest_fixes.py

Some apps open a flat Android launcher that then starts a separate VR activity (for example WiiCompiled). Shown with Lepton's flat window, that window stays in view after the VR part starts. This makes the VR activity the one Lepton starts (its LAUNCHER category), so the app opens in VR with no flat window. Everything only the launcher does (choosing or importing content) is skipped: turn it off for a run when you need the launcher, and turn off "Show the app's Android window".

#Allow swapchains larger than 4096 px

Allows very large pictures (8K video, theaters) instead of quitting.

  • frame.swapchain_limit · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Video player (…): creates swapchains larger than 4096 px (8K video, theater textures), which OVRPort's dispatcher aborts on.
  • Suggested (on): Recommended for every game: OVRPort aborts on swapchains larger than 4096 px; the Frame's runtime handles them.
  • Suggested by launch-test signatures:
    • swapchain-size-abort (fatal): The game crashed creating a very large image (over 4096 px, for example in video players).
  • Source: patches/frame/swapchain_limit.py

OVRPort's OpenXR dispatcher aborts the app ('Wrong createInfo size', SIGABRT in libopenxr_loader.so xrCreateSwapchain) when a swapchain is wider or taller than 4096 px, which video players do for 8K video or big theater textures (for example 4XVR). Raises the guard to 16384 px so the Frame's runtime (8192 px max) decides instead.

#Team Beef ports: treat the Frame as a Meta headset

Lets Team Beef ports (for example Lambda1VR) start on the Frame.

  • frame.tbxr_vendor
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Team Beef port: it picks its OpenXR setup by headset maker, which the Frame reports as "valve".
  • Catalog games (1): Lambda1VR.
  • Source: patches/frame/tbxr_vendor.py

Team Beef's ports (for example Lambda1VR, RTCWQuest) load an OpenXR library named after the headset maker and pick their VR setup by maker; for "valve" they stop at start (libopenxr_loader_valve.so not found) or take the Pico path. Adds that library and lets them take the Meta path.

#GL shim for Unity (no multisampled render-to-texture)

Stops a gray or frozen screen in Unity games that turn on anti-aliasing while running (for example The Room VR).

  • frame.unity_gl_shim
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unity GLES game that may switch to MSAA at runtime: hide multisampled render-to-texture, which crashes the Frame's GL driver (for example The Room VR).
  • Catalog games (10): Audica, BattleSisters, Beat Saber, Clockwork, Down the Rabbit Hole, End Space, Gravity Lab, Jurassic World Aftermath Collection and 2 more.
  • Suggested by launch-test signatures:
    • unreal-msrtt-crash (fatal): The game's graphics crashed a few seconds after start.
  • Source: patches/frame/vrapi_bridge.py

Loads the GL shim into a Unity GLES game and hides GL_EXT_multisampled_render_to_texture (and the multiview variant). Some Unity games switch their eye buffer to 4x MSAA at runtime; the Frame only gives single-sampled swapchains, Unity then renders through multisampled render-to-texture and Mesa/Zink crashes (SIGSEGV in libgallium_dri.so on the render thread: gray or frozen screen, for example The Room VR). Hidden, Unity uses an ordinary MSAA buffer and resolves it. Unity's multiview stays on (gl_hide_multiview defaults to 0 here).

#Unity: render each eye separately (no multiview)

Draws each eye separately. Try it when one eye shows a gray or broken picture.

  • frame.unity_multipass · revision 2
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (1): I Am Cat.
  • Source: patches/frame/unity_runtime.py

Oculus XR Plugin games render both eyes in one pass (multiview) on Android. If one eye shows only effects or gray (for example I Am Cat), rendering each eye in its own pass can fix it, at some GPU cost. Rewrites OculusSettings.GetStereoRenderingMode and its inlined read in OculusLoader.Initialize -> MultiPass in libil2cpp.so (found with Cpp2IL). Try it when one eye is wrong.

#Unity: disable MSAA

Turns off a smoothing setting that crashes some older Unity games on the Frame.

  • frame.unity_no_msaa
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Legacy VrApi Unity game on GLES with MSAA (… quality levels): multisampled render-to-texture hangs the Frame's GL driver (for example Sniper Elite VR).
  • Offered (off): GLES Unity game with MSAA on (… quality levels); enable if it hangs the GPU ('zink: DEVICE LOST').
  • Catalog games (6): Audica, BattleSisters, Jurassic World Aftermath Collection, Sniper Elite VR, SUPERHOT VR, The Room VR.
  • Suggested by launch-test signatures:
    • zink-device-lost (fatal): The GPU hung, so the game froze or closed.
  • Source: patches/frame/unity_no_msaa.py

Sets Unity QualitySettings antiAliasing to 0. Unity's multisampled render-to-texture path can hang the Frame's GL driver ('zink: DEVICE LOST', for example Sniper Elite VR). Try it for GLES Unity games that freeze or crash the GPU.

#Unity: skip OVROverlay layers (fades, splash screens)

Stops a gray screen crash in some Unity games by skipping their overlay layers (for example The Room VR).

  • frame.unity_no_overlay_copy
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (2): The Room VR, The Thrill Of The Fight.
  • Suggested by launch-test signatures:
    • unity-render-crash (fatal): The game's graphics crashed, so the picture freezes or stays gray.
  • Source: patches/frame/unity_runtime.py

Meta's OVROverlay copies a texture into its own compositor layer every frame. For some games (for example The Room VR's screen fade, a 4x4 overlay) that copy crashes the Frame's GL driver: SIGSEGV in libgallium_dri.so on Unity's render thread right after a tiny xrCreateSwapchain, gray or frozen screen. Rewrites OVROverlay.PopulateLayer -> false in libil2cpp.so (found with Cpp2IL): overlays are skipped (fades become instant cuts, overlay splash screens don't show). Only for games with this crash: menus drawn as overlays would disappear too.

#Unity: start VR without Meta's system apps

Lets older Unity games start VR without Meta's system apps (they'd stay on a 2D screen).

  • frame.unity_oculus_check · revision 5
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unity with built-in Oculus support: it checks for Meta's system apps before starting VR, else it runs as a 2D app (for example Accounting+, BattleSisters).
  • Catalog games (8): Accounting+, Audica, BattleSisters, End Space, Jurassic World Aftermath Collection, Sniper Elite VR, SUPERHOT VR, The Room VR.
  • Suggested by launch-test signatures:
    • unity-vr-device-none (fatal): Unity didn't start VR, so the game runs as a hidden 2D app.
  • Source: patches/frame/unity_oculus_check.py

Unity's built-in Oculus support (Unity 2017–2019) only starts VR when Android has Meta's com.oculus.systemactivities package; without it the game runs as a 2D app (the Android home screen or a black window, for example Accounting+, BattleSisters). Points that package name in libunity.so at "android", which always exists. Games on Unity's built-in VR (2017–2018, and 2019 without the Oculus XR Plugin) also get the frame wait their legacy frame loop never makes (libfp_ovrp.so calls ovrp_WaitToBeginFrame before ovrp_Update2; without it no frame starts, the dashboard freezes or the GPU hangs). Per game, the settings ovrp_begin_gate (a freeze at the first scene switch) and ovrp_hold_physics (hands trailing the controllers) switch on two more frame-loop fixes (for example Sniper Elite VR). The shim also counts a newly pressed trigger or A/B/X/Y as a mouse click (Input.GetMouseButtonDown), which Go-era screens wait for (for example Accounting+'s motion warning) and which Lepton never delivers.

#Unity: keep MSAA off at runtime (OVRManager)

Keeps a smoothing setting off that the game turns on itself and that can freeze the Frame.

  • frame.unity_runtime_msaa_off · revision 2
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): GLES Unity game whose OVRManager turns 4x MSAA on at runtime: multisampled render-to-texture can hang the Frame's GPU.
  • Catalog games (15): Audica, BattleSisters, Beat Saber, Clockwork, Down the Rabbit Hole, End Space, Gravity Lab, Jurassic World Aftermath Collection and 7 more.
  • Suggested by launch-test signatures:
    • unity-render-crash (fatal): The game's graphics crashed, so the picture freezes or stays gray.
    • unity-runtime-msaa (info): The game turns MSAA on at runtime, which can hang the Frame's GPU.
    • zink-device-lost (fatal): The GPU hung, so the game froze or closed.
  • Source: patches/frame/unity_runtime.py

Meta's OVRManager switches Unity to the headset's recommended MSAA level (4x) while the game runs, whatever its quality settings say (log: "Switching to the recommended level"). Multisampled render-to-texture on GLES can hang the Frame's GPU, up to a restart of the whole headset (for example Lucky's Tale in a menu) or a crash of its GL driver (for example The Room VR, whose own code sets 4x). Rewrites OVRDisplay.recommendedMSAALevel -> 0 and makes QualitySettings.antiAliasing's setter do nothing in libil2cpp.so (found with Cpp2IL), so MSAA stays off.

#Make Unity text fields work

Lets you type into this app's text fields on the Frame (they'd close at once).

  • frame.unity_text_input · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unity app with text fields (…): they close at once on the Frame because it has no system keyboard.
  • Catalog games (55): AgeOfJoy, AllInOneSports, Ancient_Dungeon, Audica, BattleSisters, Beat Saber, Beat Saber (co-existence build), Blade & Sorcery: Nomad and 47 more.
  • Source: patches/frame/unity_text_input.py

Unity's TMP_InputField / InputField wait for Android's on-screen keyboard and close themselves a frame later when there is none (Lepton has no on-screen keyboard; Meta's system keyboard does this on a Quest), so a selected text field only flashes a caret. Rewrites TouchScreenKeyboardShouldBeUsed -> false and isKeyboardUsingEvents (TMP) / InPlaceEditing (uGUI) -> true in libil2cpp.so, found per game with Cpp2IL (downloaded on first use), so fields stay selected and take key presses: Steam's keyboard (with "Show the app window") or Type on Frame from the PC.

#Unity: headset always counts as worn

Counts the headset as worn, so games that only move the player while it's worn get head tracking and controls (for example BONELAB).

Unity's Oculus XR Plugin asks OVRPlugin whether the headset is worn; on the Frame the answer turns to "not worn" a few seconds after start. Games that only move the player while the headset is worn then show a frozen body with no head tracking and no controls (for example BONELAB). Reports the headset as worn; taking it off still pauses the game through the session's focus.

#GL shim for Unreal (no multisampled render-to-texture)

Stops a crash a few seconds after start in some Unreal games with anti-aliasing (for example Star Wars Pinball VR).

  • frame.unreal_gl_shim
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (1): Star Wars Pinball VR.
  • Suggested by launch-test signatures:
    • unreal-msrtt-crash (fatal): The game's graphics crashed a few seconds after start.
  • Source: patches/frame/vrapi_bridge.py

Loads the GL shim into an Unreal GLES game and hides GL_EXT_multisampled_render_to_texture. Unreal's mobile MSAA renders through multisampled render-to-texture, and the Frame's GL driver (Mesa/Zink) can crash on it: SIGSEGV with fault address 0x10000 in libgallium_dri.so on the RHIThread a few seconds after start (Zink looks up a render-pass cache slot past its end, for example Star Wars Pinball VR). Hidden, Unreal renders without that path. Unreal's multiview stays on: Unreal only uses it when GL_OVR_multiview_multisampled_render_to_texture is listed too, so for Unreal the shim keeps that one visible and draws its multiview MSAA attachments single-sampled (glFramebufferTextureMultiviewOVR).

#Unreal: stand-ins for OVRPlugin functions OVRPort lacks

Lets older Unreal games start VR on the Frame (for example Star Wars Pinball VR).

  • frame.unreal_ovrp_entrypoints
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unreal looks up OVRPlugin function(s) OVRPort's OVRPlugin lacks: ……. Without them Unreal starts no VR.
  • Catalog games (1): Star Wars Pinball VR.
  • Source: patches/frame/unreal_ovrp.py

Unreal's Oculus module looks up every OVRPlugin function it was built against and starts no VR when one is missing; OVRPort's OpenXR OVRPlugin lacks some old ones (for example ovrp_GetPTWNear, which Unreal 4.25 builds like Star Wars Pinball VR look up). The game then never starts an OpenXR session and crashes a few seconds in. Adds a generated library to libOVRPlugin.so with a stand-in for each missing function that reports failure (ovrpFailure), so Unreal's Oculus support starts. The functions OVRPort has are untouched.

#Unreal: Quest controller bindings (RPOC key map)

Makes grip, trigger and touch controls reach the game's hands (it picked the empty Gear VR controls on the Frame, for example Vader Immortal).

  • frame.unreal_quest_keymap
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (3): Vader Immortal: Episode I, Vader Immortal: Episode II, Vader Immortal: Episode III.
  • Source: patches/frame/unreal_santacruz.py

ILMxLAB's Unreal games (for example Vader Immortal) bind their controls through URPOCKeyMapManagerComponent, which for an Oculus headset picks the Quest ("SantaCruz") or the Gear VR key set by IsRunningOnSantaCruz. On the Frame it picks Gear VR, which is empty in a Quest build: grip, trigger and touch reach Unreal but never the game's hands (grabbing does nothing). Removes the branch to the Gear VR set in the Oculus case of the key selector both action and axis mappings use. Found by Klownicle (GitHub #49).

#Unreal: don't wait for the Quest shader precompile

Lets the game leave its loading screen: it waited for a Quest-only step that never starts on the Frame (for example Vader Immortal).

  • frame.unreal_quest_precompile
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (3): Vader Immortal: Episode I, Vader Immortal: Episode II, Vader Immortal: Episode III.
  • Source: patches/frame/unreal_santacruz.py

ILMxLAB's Unreal games (for example Vader Immortal) wait on their loading card until UVRUtils::GetQuestShaderPrecompilePercent reaches 100 %. The precompile only starts on a Quest (IsRunningOnSantaCruz); on any other device the function returns 0.0, so the loading card (a portrait with a progress bar) never ends. Makes that non-Quest branch return 1.0. The Quest branch and the game's normal shader compiling stay as they are. Found by Klownicle (GitHub #49).

#Unreal: start without the OBB check

Starts Unreal games without re-checking their data file (they'd seem to hang on an invisible check screen).

  • frame.unreal_skip_obb_check · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Unreal checks the OBB's contents before starting (bVerifyOBBOnStartUp); on the Frame a failed or slow check can't be seen and the game seems to hang.
  • Suggested by launch-test signatures:
    • unreal-obb-check-stuck (fatal): The game stays on Unreal's OBB check screen (DownloaderActivity), which the Frame doesn't show, and never starts VR (for example Contractors, GitHub #159).
  • Source: patches/frame/unreal_obb_check.py

Unreal games can check their whole data file (.obb) before starting (bVerifyOBBOnStartUp). On the Frame that check's progress and error screens are invisible (Lepton runs VR games without an Android window), so the game seems to hang on its DownloaderActivity, for example Contractors. This turns the check off in the manifest; Unreal still checks that the OBB is there with the right size, so a missing or wrong-version OBB still stops the game.

#Unreal: thumb follows the capacitive touches

Makes the hands' thumbs follow what your thumb touches (they always pointed up: the Frame doesn't sense a thumb hovering, for example Vader Immortal).

  • frame.unreal_thumb_touch
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (7): Phantom: Covert Ops, Robo Recall, Star Wars: Tales from the Galaxy's Edge, Time Stall, Vader Immortal: Episode I, Vader Immortal: Episode II, Vader Immortal: Episode III.
  • Source: patches/frame/unreal_thumb_touch.py

Unreal 4's Oculus input sets the ThumbUp axis (games animate the hand's thumb with it) from Meta's near-touch sensing, which the Frame never reports: the thumb always points up. Uses the touches instead (left X/Y/stick/thumb rest, right A/B/stick/thumb rest). Changes three instructions in OculusInput::SendControllerEvents, only where the code matches exactly (UE4 Oculus games of one engine generation, for example Vader Immortal, Robo Recall). Found by Klownicle (GitHub #49).

#Vivox voice chat: skip Android 12 audio routing

Lets games with Vivox voice chat start on the Frame (they'd crash on an Android 12 audio call).

  • frame.vivox_audio_route · also for 2D apps
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Vivox voice chat: it calls Android 12 audio methods, which Lepton (Android 11) lacks, and crashes.
  • Suggested by launch-test signatures:
    • vivox-api31 (fatal): The game's Vivox voice-chat SDK calls Android 12 audio-routing methods (AudioManager communication devices) without checking the Android version; Lepton runs Android 11, so the app crashes (for example Green Hell VR).
  • Source: patches/frame/vivox_audio_route.py

Vivox's voice-chat SDK (for example Green Hell VR) checks the audio route with Android 12 methods (AudioManager communication devices) without checking the Android version; Lepton runs Android 11, so the game crashes at start with a NoSuchMethodError. Those Vivox methods return at once instead (an in-place edit of classes.dex); voice chat keeps the default audio route.

#Vulkan: drop invalid render-pass pointers

Cleans up graphics data that crashes some Unreal games on the Frame.

  • frame.vk_sanitize · on by default
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): Own-engine game: applied when one of its libraries loads Vulkan by name (for example Roblox); keeps Lepton's Fossilize layer from crashing on uninitialized pointers.
  • Suggested (on): Unreal game: applied automatically when the engine loads Vulkan by name; keeps Lepton's Fossilize layer from crashing on uninitialized pointers (for example Deadpool VR).
  • Catalog games (1): WiiCompiled VR.
  • Suggested by launch-test signatures:
    • fossilize-renderpass (fatal): A Vulkan layer in Lepton (Fossilize) crashed while the game set up its graphics.
    • unreal-vulkan-driver-crash (fatal): The Frame's Vulkan driver crashed on a call from Unreal.
  • Source: patches/frame/vk_sanitize.py

Some engines leave the pNext of unused Vulkan attachment references uninitialized. The Frame's driver never reads it, but Lepton always loads Steam's Fossilize shader-cache layer, which follows it and crashes on the first frame (SIGSEGV in libVkLayer_fossilize.so from FVulkanRenderPass, for example Deadpool VR). Loads Vulkan through a small shim that keeps valid pointers and drops only unreadable ones or ones pointing at the wrong structure type. It also drops a depth resolve named in a subpass without a depth attachment, which crashes the Frame's driver at the first render pass (for example Metro Awakening).

#VrApi → OpenXR bridge

Lets games built on Meta's oldest VR interface run on the Frame.

  • frame.vrapi_bridge · experimental
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested (on): The engine calls libvrapi.so directly; OVRPort can't translate it.
  • Conflicts with: frame.vrapi_stub
  • Catalog games (3): BlazeRush, Path of the Warrior, The Climb 2.
  • Suggested by launch-test signatures:
    • direct-vrapi (warning): The game uses Meta's VrApi directly and needs the VrApi bridge.
  • Source: patches/frame/vrapi_bridge.py

Replaces libvrapi.so with a VrApi→OpenXR bridge (Android-XR-Bridge/OVRPort fork, GPL-3.0, patched for the Frame: GLES sessions, cylinder→quad layers, sRGB format fallback, 30 s VR-mode deadline, emulated time conversion). Needed when the engine calls VrApi itself instead of through OVRPlugin (for example The Climb 2, Path of the Warrior); OVRPort cannot translate those.

#Quiet Meta's VrApi loader (OpenXR games)

Stops Meta's old VR library from closing the game at start (for example Jurassic World Aftermath).

  • frame.vrapi_stub
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Conflicts with: frame.vrapi_bridge
  • Catalog games (2): Jurassic World Aftermath Collection, ZombielandVR.
  • Suggested by launch-test signatures:
    • vrapi-before-init (fatal): Meta's VrApi loader stopped the game.
  • Source: patches/frame/vrapi_stub.py

Some OpenXR games still ship Meta's VrApi loader and call it a few times without starting VrApi (for example Jurassic World Aftermath); Meta's loader then stops the game ("vrapi_SetPropertyInt was called before vrapi_Initialize()"). Replaces it with a library that has the same functions, each doing nothing. Only for games whose VR runs through OVRPlugin on OpenXR.

#OpenGL ES: shader fixes (Vulkan layer under Zink)

Repairs shaders that hang the graphics chip at certain effects, from the game's recipe (for example Vader Immortal's lightspeed jump).

  • frame.zink_shader_fix
  • Changes: Changes the APK (a rebuild and reinstall apply it).
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Catalog games (1): Vader Immortal: Episode I.
  • Source: patches/frame/zink_shader_fix.py

Loads FramePort's shader-fix Vulkan layer into an OpenGL ES game. On the Frame, OpenGL ES runs on Zink (Mesa's GL on Vulkan); the layer sits between Zink and the driver and inserts the words of the adapter setting zink_shader_fix into the SPIR-V modules whose size and SHA-256 match (every other module is untouched), for example stores that set loop counters and accumulators a shader reads before writing, which hang the GPU (Vader Immortal's lightspeed jump; found by Klownicle, GitHub #49). Does nothing without zink_shader_fix (or zink_shader_dump) in the recipe. The layer adds itself to Android's Vulkan debug layer list for the game's process only.

#Game settings

Settings of FrameBridge, FramePort's OpenXR layer inside every converted Quest game. Most can be changed on the Frame later without a rebuild (game page → Game settings).

#Pointer start

Moves where the pointer starts, forward or back.

  • adapter.aim_forward
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Controllers → "Pointer start" (advanced): slider -0.3–0.3 in steps of 0.01.
  • Source: patches/settings.py

Moves where the pointing ray starts forward (+) or back (−).

#Pointer angle

If the pointer doesn't hit what you aim at, tilt it up or down.

  • adapter.aim_pitch
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Controllers → "Pointer angle": slider -30–30 in steps of 1.
  • Source: patches/settings.py

Tilts the controllers' pointing ray up (+) or down (−), for games whose pointer doesn't hit what you aim at.

#Pointer turn

Turns the pointer left or right.

  • adapter.aim_yaw
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Controllers → "Pointer turn" (advanced): slider -30–30 in steps of 1.
  • Source: patches/settings.py

Turns the controllers' pointing ray left (+) or right (−).

#Use controllers

Turn off only for games you play with your hands instead of controllers.

  • adapter.controller_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested (on), value 0: Hand tracking is required by the game: pass hands through instead of reporting Touch controllers (for example Silhouette).
  • Options:
    • Value: int, default 1 (always written).
    • Game settings → Controllers → "Use controllers".
  • Catalog games (1): Silhouette.
  • Source: patches/settings.py

Reports Frame controllers as Oculus Touch and hides synthetic hand tracking. Set 0 for games that require hand tracking (for example Silhouette).

#Show Steam Frame controllers

For games that show the headset's own controllers. Takes effect after a reinstall.

  • adapter.controller_models
  • Changes: Game setting, stored in the build: needs a rebuild.
  • Suggested (on), value 1: The game asks the headset for its controller models: show Steam Frame controllers instead of Quest Touch controllers.
  • Options:
    • Value: int, default 0.
    • Game settings → Controllers → "Show Steam Frame controllers".
  • Catalog games (3): SynthRiders, VR HOT Quest, Walkabout Mini Golf.
  • Suggested by launch-test signatures:
    • render-model-requested (info): The game shows Quest controllers (or none) because the Frame doesn't provide controller models.
  • Source: patches/settings.py

Games that ask the headset for its controller models (Meta's runtime controller models, XR_FB_render_model) get the Steam Frame controllers instead of Quest Touch controllers. The models come from the Frame's own SteamVR and are converted on the Frame at install time. Games that ship their own controller meshes aren't affected. Turning it on needs a rebuild (it adds a small library in front of OVRPort's loader).

#Stand in for cube layers

Keeps games running that use a 360° cube layer the Frame lacks (for example Budget Cuts Ultimate). Leave it on.

  • adapter.cube_standin
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Stand in for cube layers" (advanced).
  • Source: patches/settings.py

The Frame's runtime has no cube-map layers and refuses their swapchains; OVRPlugin then crashes when it submits the next frame (for example Budget Cuts Ultimate). FrameBridge serves such a swapchain itself (a GL cube map, GLES games) and drops its layers, so the game runs on without that layer.

#Show curved menus and screens

The Frame can't show curved panels; this shows them as gently bent strips.

  • adapter.cylinder_strips
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Menus and screens → "Show curved menus and screens".
  • Source: patches/settings.py

Cylinder layers (curved menus and movie screens, for example 4XVR), which the Frame's runtime lacks, are shown as a few flat strips along the curve. 0 = drop them. 360° (equirect) layers can't be shown on the Frame.

#Show 360° backgrounds and videos

Video players' virtual theaters and 360° videos would otherwise stay black.

  • adapter.equirect_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested (on), value 1: The game draws 360° layers (for example a video player's theater or 360° videos), which the Frame's runtime can't show: show them as panels around you.
  • Options:
    • Value: int, default 0.
    • Game settings → 360° pictures and video → "Show 360° backgrounds and videos".
  • Catalog games (4): 4XVR Video Player, Into The Radius 2, Pinball FX VR, Riven.
  • Suggested by launch-test signatures:
    • equirect-layers-dropped (warning): The game's 360° pictures (for example a video player's theater or 360° videos) are missing because the Frame's runtime can't show equirect layers.
  • Source: patches/settings.py

360° (equirect) layers, for example a video player's virtual theater or 360° videos (for example 4XVR), which the Frame's runtime lacks, are drawn by a background thread into a layer behind the game's own picture: the 360° image is converted only when it changes (a theater once, a 360° video once per video frame) and the view is drawn for each frame's head pose. GLES games only; without it these layers are missing (black).

#360° detail

Higher keeps more detail but uses more memory.

  • adapter.equirect_face
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1536.
    • Game settings → 360° pictures and video → "360° detail" (advanced): Low (1024), Normal (1536), High (2048), Maximum (2730); shown while adapter.equirect_emul is on.
  • Source: patches/settings.py

Maximum size in pixels of each face of the cube the 360° image is converted to (256–2730). Higher is sharper but uses more GPU memory.

#360° picture orientation

Only if 360° pictures show wrongly.

  • adapter.equirect_flip
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → 360° pictures and video → "360° picture orientation" (advanced): Normal (0), Upside down (1), Mirrored (2), Upside down and mirrored (3), Turned around (4); shown while adapter.equirect_emul is on.
  • Source: patches/settings.py

Only if 360° pictures show wrongly: 1 = upside down, 2 = mirrored, 4 = turned around (add values to combine).

#360° video frame rate limit

Must be at least the video's own frame rate.

  • adapter.equirect_fps
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 60.0.
    • Game settings → 360° pictures and video → "360° video frame rate limit" (advanced): No limit (0), 24 (24), 30 (30), 60 (60), 90 (90); shown while adapter.equirect_emul is on.
  • Source: patches/settings.py

At most this many redraws per second of a 360° layer (0 = no limit). Video players need at least the video's frame rate.

#360° sharpness

Higher is sharper but needs more power.

  • adapter.equirect_res
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1536.
    • Game settings → 360° pictures and video → "360° sharpness" (advanced): Low (1024), Normal (1536), High (2048), Very high (3072); shown while adapter.equirect_emul is on.
  • Source: patches/settings.py

Size in pixels per eye of the 360° background, redrawn every frame on a background thread (512–4096). Higher is sharper but costs more GPU time per frame.

#360° 3D

Shows 3D 360° pictures flat if they look doubled.

  • adapter.equirect_stereo
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → 360° pictures and video → "360° 3D" (advanced): As the game sends it (0), Flat (2); shown while adapter.equirect_emul is on.
  • Source: patches/settings.py

Stereo (3D) 360° layers: 0 = as the game sends them, 2 = flat (the left image to both eyes).

#Per-eye diagnostics (log)

Logs details when one eye looks wrong. No effect on the game.

  • adapter.eye_debug
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Per-eye diagnostics (log)" (advanced).
  • Source: patches/settings.py

For one eye looking wrong (for example a jittering right eye): logs each eye's submitted pose against a fresh one, the eye-to-eye relation and when each eye's image was released, also into framebridge.log in the game's storage (some games stop Android's log early). No effect on the game.

#Fix upside-down menus

Turns menus and text the right way up.

  • adapter.flip_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Menus and screens → "Fix upside-down menus".
  • Source: patches/settings.py

Blit quads flagged XrCompositionLayerImageLayoutFB VERTICAL_FLIP upside down (Vulkan). Fixes UI panels and text that show upside down (for example Assassin's Creed Nexus).

#Rotate panels 180°

Older way to turn upside-down panels; prefer Fix upside-down menus.

  • adapter.flip_quads
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Rotate panels 180°" (advanced).
  • Source: patches/settings.py

Older workaround for upside-down quads: rotates them 180° (quads are single-sided; prefer flip_emul).

#Don't pause on short interruptions

For games that pause or recenter when the headset briefly loses focus.

  • adapter.focus_hold
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Menus and screens → "Don't pause on short interruptions".
  • Catalog games (4): 4XVR Video Player, BattleGlide, Blade & Sorcery: Nomad, Into The Radius 2.
  • Suggested by launch-test signatures:
    • focus-dip-teleport (warning): The view jumps because the game moves the player after the Frame's brief focus dips.
  • Source: patches/settings.py

Hides the Frame's brief focus dips (up to focus_hold_ms) once the game has been focused for a second. On by default: the Frame's wear sensor flickers "HMD off" for 0.5-2 s while worn, and many games pause or recenter every time (for example Blade & Sorcery, Lucky's Tale).

#Ignore focus dips up to

Longer for headsets that briefly think they're off your head.

  • adapter.focus_hold_ms
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 5000.0.
    • Game settings → Menus and screens → "Ignore focus dips up to" (advanced): slider 500–3000 in steps of 100; shown while adapter.focus_hold is on.
  • Catalog games (2): Blade & Sorcery: Nomad, Into The Radius 2.
  • Source: patches/settings.py

focus_hold hides focus dips up to this long (100-5000). Longer for a headset whose wear sensor flickers ("HMD off" for 0.5-2 s while worn, for example Blade & Sorcery pausing); taking the headset off or the system menu pauses the game only after this long.

#Hide Quest foveation

Hides a Quest-only way of saving GPU power that the Frame lacks. Leave it on.

  • adapter.foveation_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1 (always written).
    • Game settings → Troubleshooting → "Hide Quest foveation" (advanced).
  • Source: patches/settings.py

Hides Quest foveation extensions the Frame runtime lacks.

#Hide fast anti-aliasing (OpenGL ES)

For Unity games that crash when they turn on anti-aliasing (for example The Room VR).

  • adapter.gl_hide_msrtt
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Hide fast anti-aliasing (OpenGL ES)" (advanced).
  • Catalog games (1): BlazeRush.
  • Source: patches/settings.py

GL shim only: hide GL_EXT_multisampled_render_to_texture(2) (Zink crashes rendering Unity's runtime MSAA eye buffer through it, for example The Room VR).

#Draw each eye separately (OpenGL ES)

For older games whose picture stays black on the Frame (for example Path of the Warrior).

  • adapter.gl_hide_multiview
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Draw each eye separately (OpenGL ES)" (advanced).
  • Catalog games (1): BlazeRush.
  • Source: patches/settings.py

GL shim only: hide GL_OVR_multiview so all passes use single-view shaders. For GLES games whose multiview shaders fail on single-view render targets (for example Path of the Warrior).

#GL shim: high-precision vertex shaders

Computes some of the game's effects more precisely, so they don't draw streaks or flashes (for example BlazeRush's particles). Comes from a game's recipe.

  • adapter.gl_highp_markers · revision 2
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: str, default empty.
    • Not in the Game settings dialog (set by a recipe or the CLI).
  • Catalog games (1): BlazeRush.
  • Source: patches/settings.py

GL shim (frame.gl_shim): vertex shaders whose source contains every '|'-separated text compute in highp: whole-word mediump becomes highp on every line without the words in, out or uniform (the shader's interface keeps its precision). For effects that draw streaks or flashes from mediump rounding on the Frame (for example BlazeRush's particles: in uvec2 inBoneIndices;|uniform InstanceData|void main()). Pair it with a new shader cache name if the game caches compiled programs. Comes from a game's recipe.

#GL shim: integer vertex inputs

Shows models whose shapes come from bone data the Frame's graphics driver misreads (for example BlazeRush's cars). Comes from a game's recipe.

  • adapter.gl_int_attribs · revision 2
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Not in the Game settings dialog (set by a recipe or the CLI).
  • Catalog games (1): BlazeRush.
  • Source: patches/settings.py

GL shim (frame.gl_shim): shader inputs declared as integers (int/uint, ivecN/uvecN) whose vertex data the game set up with glVertexAttribPointer (as floats) are set up again with glVertexAttribIPointer before each draw. Qualcomm's Quest driver read the raw integers anyway; the Frame's GL driver converts them to floats, so skinned models using bone indices vanish (for example BlazeRush's car bodies and controllers; Klownicle's guide, GitHub #57). Comes from a game's recipe.

#Flat panel diagnostics (log)

Logs details when flat panels stay black. No effect on the game.

  • adapter.gl_mv_debug
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Flat panel diagnostics (log)" (advanced).
  • Source: patches/settings.py

Diagnostics for frame.gl_multiview_fbo: checks for GL errors after every single-view draw of a multiview shader and logs counters every 5 seconds (tag GLMV in launch.log).

#Fix freezes when controllers vibrate

For games that freeze the Frame when a controller vibrates (for example Lucky's Tale). Needs a rebuild.

  • adapter.haptic_fix · revision 2
  • Changes: Game setting, stored in the build: needs a rebuild.
  • Suggested (on), value 1: Meta's OVRPlugin vibrates controllers through OVRPort's loader, which turns some vibrations into gigabyte allocations that freeze the Frame (for example Lucky's Tale, BattleSisters): vibrations are converted before they reach it.
  • Options:
    • Value: int, default 0.
    • Game settings → Controllers → "Fix freezes when controllers vibrate" (advanced).
  • Catalog games (39): AgeOfJoy, Ancient_Dungeon, Audica, BattleSisters, Caves, Clockwork, cubism, Deep Cuts and 31 more.
  • Source: patches/settings.py

Routes OVRPlugin through FramePort's extension shim, which turns Meta's amplitude-envelope vibrations into plain ones: OVRPort's loader reads their nanosecond duration as seconds and allocates gigabytes, freezing the Frame when the game vibrates a controller (for example Lucky's Tale's save slots, GitHub #9). Needs a rebuild.

#Vibration strength

Turn it down if controller vibrations are too strong.

  • adapter.haptic_scale
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 1.0.
    • Game settings → Controllers → "Vibration strength": slider 0–1 in steps of 0.05.
  • Source: patches/settings.py

Scales every controller vibration the game asks for (0-1): plain vibrations, Meta's amplitude envelopes and PCM buffers. For games whose vibrations feel much stronger than on a Quest.

#Turn off space warp

For games whose picture flickers or smears (for example Into The Radius 2).

  • adapter.hide_space_warp
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Offered (off), value 1: Unreal Engine 5 game with Meta's space warp: turn on if the picture flickers or smears (for example Into The Radius 2).
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Turn off space warp" (advanced).
  • Catalog games (4): Into The Radius 2, Metro Awakening, Pinball FX VR, The Boys VR.
  • Suggested by launch-test signatures:
    • space-warp-used (info): The game uses Meta's space warp (it renders half of its frames plus motion vectors, and the runtime makes up the rest).
  • Source: patches/settings.py

Hides XR_FB_space_warp, so the game renders every frame itself instead of half of them plus motion vectors (Application SpaceWarp). For games whose picture flickers or smears on the Frame (for example Unreal Engine 5 games such as Into The Radius 2).

#Controller input diagnostics (log)

Logs details when buttons do nothing or the wrong thing. No effect on the game.

  • adapter.input_diag
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Controller input diagnostics (log)" (advanced).
  • Source: patches/settings.py

For buttons that do nothing or the wrong thing: logs each controller profile the game suggests bindings for and whether the runtime accepts it (with every path of a rejected one), which profile the runtime reports for each hand (a game without Steam Frame bindings gets SteamVR's Touch remap), OpenXR functions the game looks up that the runtime lacks, and failing input, vibration and performance calls. Each line once. No effect on the game.

#Extra diagnostics (log)

Logs details for troubleshooting. No effect on the game.

  • adapter.layer_debug
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Extra diagnostics (log)" (advanced).
  • Source: patches/settings.py

Logs details for debugging: composition layers and swapchains, focus changes, play-space creation, pointer vs grip poses, refresh rates. No effect on the game.

#Drop broken layers

Skips picture layers the Frame would refuse. Leave it on.

  • adapter.layer_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Drop broken layers" (advanced).
  • Source: patches/settings.py

Drop layers whose swapchain failed or whose extension isn't enabled.

#Vulkan format workaround

Experimental. Leave it off unless asked to test it.

  • adapter.mutable_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Vulkan format workaround" (advanced).
  • Source: patches/settings.py

Experimental Vulkan mutable-format workaround.

#Unity frame loop: wait for skipped frames

For older Unity games that freeze at the first scene change (for example Sniper Elite VR). Can make loading screens stutter.

  • adapter.ovrp_begin_gate
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Unity frame loop: wait for skipped frames" (advanced).
  • Catalog games (1): Sniper Elite VR.
  • Source: patches/settings.py

Unity's built-in Oculus frame loop (frame.unity_oculus_check): before each frame wait, wait up to 50 ms for the last waited frame to begin and skip the wait if it doesn't. Fixes a freeze at the first scene switch (for example Sniper Elite VR); in other games it can make loading screens stutter.

#Steadier hands (older Unity)

For older Unity games whose hands trail the controllers (for example Sniper Elite VR). In others the hands lag.

  • adapter.ovrp_hold_physics
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Steadier hands (older Unity)" (advanced).
  • Catalog games (1): Sniper Elite VR.
  • Source: patches/settings.py

Unity's built-in Oculus frame loop (frame.unity_oculus_check): don't pass Unity's physics-step pose update on, so the hands use the frame's display-time poses. Fixes hands trailing the controllers in some games (for example Sniper Elite VR); in others it makes the hands lag (for example BattleSisters).

#See your room

Shows the Frame's cameras where the game expects passthrough.

  • adapter.passthrough_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Mixed reality → "See your room".
  • Suggested by launch-test signatures:
    • passthrough-missing (error): The game needs Meta passthrough (the camera view), which the Frame lacks; the adapter emulates it.
  • Source: patches/settings.py

XR_FB_passthrough via ALPHA_BLEND (Frame grayscale cameras).

#Steadier head tracking

For games that judder or shimmer while you hold your head still (for example I Am Cat).

  • adapter.pose_consistency · revision 2
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Picture → "Steadier head tracking" (advanced).
  • Catalog games (1): I Am Cat.
  • Source: patches/settings.py

Repeat xrLocateViews queries for the same display time get the first, fully tracked answer again. Games that ask several times per frame got slightly different poses and rendered parts of the frame with different heads: judder (for example I Am Cat; proposed by Klownicle, GitHub #8).

#Pose timing diagnostics (log)

Logs how game poses line up with the Frame's clock. No effect on the game.

  • adapter.pose_debug
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Pose timing diagnostics (log)" (advanced).
  • Source: patches/settings.py

Every 5 s, logs per located space how far the requested times are from the frame's predicted display time, and the runtime clock's offset from the monotonic clock. No effect on the game.

#Fix hands lagging behind controllers

For games whose hands trail the controllers when you move them (for example BattleSisters).

  • adapter.pose_time_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested (on), value 1: Unity's built-in Oculus support reads controller poses through OVRPlugin at its monotonic "now", seconds in the past on the Frame: they are located at the right time (for example BattleSisters, Sniper Elite VR).
  • Suggested (on), value 1: Unreal 4's Oculus input of this OVRPlugin generation asks for controller poses at OVRPlugin's own clock, which is behind the Frame's: they are located at the right time (for example Vader Immortal).
  • Options:
    • Value: int, default 0.
    • Game settings → Controllers → "Fix hands lagging behind controllers" (advanced).
  • Catalog games (8): BattleSisters, Phantom: Covert Ops, Robo Recall, Star Wars: Tales from the Galaxy's Edge, Time Stall, Vader Immortal: Episode I, Vader Immortal: Episode II, Vader Immortal: Episode III.
  • Source: patches/settings.py

Poses a game asks for at a CLOCK_MONOTONIC time, or more than 0.5 s before the frame's display time, are located at the same moment in the runtime's time (or now). Meta's OVRPlugin passes the monotonic clock on as the OpenXR time, which on the Frame runs seconds behind the runtime's clock, so its "now" poses (Unity's physics step, controller poses) came from the past: hands trailing the controllers (for example BattleSisters, Sniper Elite VR).

#Treat newer Quest controllers as Touch

For apps that only know Quest 3/Pro controllers: without it they get no buttons.

  • adapter.profile_remap
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Controllers → "Treat newer Quest controllers as Touch" (advanced).
  • Source: patches/settings.py

Apps that suggest controller bindings only for Meta's newer profiles (Touch Plus, Touch Pro), which the Frame's runtime rejects (XR_ERROR_PATH_UNSUPPORTED), get the same bindings as oculus/touch_controller instead (components Touch lacks are dropped). Without it such apps get no controller input.

#Animate fingers from touch

For games whose hands' thumbs never move when you touch the buttons or thumbstick (for example Vader Immortal).

  • adapter.proximity_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Controllers → "Animate fingers from touch" (advanced): Off (0), Thumbs (1), Thumbs and index fingers (2).
  • Source: patches/settings.py

Meta's OVRPlugin reports a thumb (or index finger) resting near the controller through XR_FB_touch_controller_proximity, which the Frame's runtime lacks: "near" stays false and games that animate the hands from it show a thumb that never moves (for example Vader Immortal; found by Klownicle, GitHub #49). Binds the game's proximity actions to the capacitive touch inputs instead: 1 = thumb (thumbstick, face buttons or thumb rest touched), 2 = also the index finger (trigger touched). Only when the runtime lacks the extension.

#Keep pictures in bounds

Stops games from hanging when their eye picture is a little too big (for example PowerWash Simulator). Leave it on.

  • adapter.rect_clamp
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Keep pictures in bounds" (advanced).
  • Source: patches/settings.py

Keeps every submitted image rect inside its swapchain. Unity can size the eye area a few pixels past the image on some Frames; SteamVR then rejects every frame (xrEndFrame -25, XR_ERROR_SWAPCHAIN_RECT_INVALID) and the game stops drawing (for example PowerWash Simulator stuck at "Waiting").

#Refresh rate

How often the picture updates. Higher is smoother if the game can keep up.

  • adapter.refresh_rate
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Picture → "Refresh rate": Game's choice (0), 72 Hz (72), 80 Hz (80), 90 Hz (90), 96 Hz (96), 108 Hz (108), 120 Hz (120), 144 Hz (144).
  • Catalog games (2): Does it Stack?, Vacation Simulator.
  • Source: patches/settings.py

Display refresh rate for this game (72, 80, 90, 96, 108, 120 or 144; 0 = the game's choice). A video's frame rate that divides the refresh rate plays smoothest (for example 30 fps at 90 Hz, 24 fps at 72 Hz).

#Wait for the game's GPU

For games where one eye flickers or jitters. Costs some speed.

  • adapter.release_wait
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Wait for the game's GPU" (advanced).
  • Source: patches/settings.py

Before a swapchain image is handed to the Frame, wait until the game's GPU work on it has finished, for games that hand over images early (an eye flickers or jitters). Costs some frame time. 2 = only after the first 60 s (compare both in one session).

#Re-create play space

Re-creates the game's play space after the first frames. For testing.

  • adapter.respace_kick
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Re-create play space" (advanced).
  • Source: patches/settings.py

Recreate spaces after the first frames (diagnostic).

#Sharpness

Higher looks sharper but needs more power; lower runs smoother. 1.0× is the game's own.

  • adapter.scale
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 1.0 (always written).
    • Game settings → Picture → "Sharpness": slider 0.5–2 in steps of 0.1.
  • Catalog games (4): 4XVR Video Player, BlazeRush, cubism, Walkabout Mini Golf.
  • Source: patches/settings.py

Multiplies the recommended eye-buffer width and height (0.5–2.0). 1.5 ≈ 2.25× pixels.

#Room depth

0 = the size of your play area.

  • adapter.scene_depth
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Mixed reality → "Room depth" (advanced): slider 0–10 in steps of 0.5; shown while adapter.scene_emul is on.
  • Source: patches/settings.py

Override the guardian depth (0 = use guardian, min 1.5 m).

#Pretend room layout

Mixed-reality games that build their level from your room get a simple room with walls.

  • adapter.scene_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested (on), value 1: Mixed-reality game that builds its level from the room model: emulate a guardian-sized room (for example Demeter).
  • Suggested (on), value 1: The game asks Meta's system for your room layout (scene), which the Frame doesn't have: emulate a room from the play area (for example VR HOT's room setup).
  • Options:
    • Value: int, default 0.
    • Game settings → Mixed reality → "Pretend room layout".
  • Catalog games (1): Demeter.
  • Suggested by launch-test signatures:
    • scene-missing (warning): The game wants Meta's room data (scene API), which the Frame lacks.
  • Source: patches/settings.py

Fake XR_FB_scene/spatial entities: a guardian-sized room with floor, ceiling and four walls, for mixed-reality games that build their level from the room (for example Demeter).

#Room height

Ceiling height of the pretend room.

  • adapter.scene_height
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 2.5.
    • Game settings → Mixed reality → "Room height" (advanced): slider 2–4 in steps of 0.1; shown while adapter.scene_emul is on.
  • Source: patches/settings.py

Ceiling height for scene_emul.

#Room width

0 = the size of your play area.

  • adapter.scene_width
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: float, default 0.0.
    • Game settings → Mixed reality → "Room width" (advanced): slider 0–10 in steps of 0.5; shown while adapter.scene_emul is on.
  • Source: patches/settings.py

Override the guardian width (0 = use guardian, min 1.5 m).

#Eye-image snapshots (diagnostics)

Saves what the game draws every few seconds, for testing without the headset.

  • adapter.snapshot
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Eye-image snapshots (diagnostics)" (advanced).
  • Source: patches/settings.py

Every N seconds, saves the left-eye image the game submits (a quarter of its size) as fb_snap_0-7.ppm in the game's files folder on the Frame. Launch tests run without anyone wearing the headset, so the headset view stays black; this shows what the game itself draws. OpenGL ES games only.

#Keep menus in place

For games whose menus or screens jump to wherever you look.

  • adapter.stable_local
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Menus and screens → "Keep menus in place".
  • Catalog games (1): 4XVR Video Player.
  • Source: patches/settings.py

Every 'local' play space the game creates lines up with the one at the start. For games whose menus or screens jump to where you look on the Frame.

#Drop layer color fades

For games whose memory use keeps growing (for example Vader Immortal). Some fades no longer show.

  • adapter.strip_color_bias
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Drop layer color fades" (advanced).
  • Source: patches/settings.py

Removes the color scale/bias (XR_KHR_composition_layer_color_scale_bias) from the game's layers, so the runtime doesn't apply it. The Frame's runtime allocates GPU memory for it every frame without freeing it, for example Vader Immortal leaked ~20 MB/s on its loading screen. Fades done this way no longer show.

#Strip depth layers

Removes depth information from the game's layers. For testing.

  • adapter.strip_depth
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Strip depth layers" (advanced).
  • Source: patches/settings.py

Remove XR_KHR_composition_layer_depth chains (diagnostic).

#Show video panels

Shows videos that games play on a flat panel (for example an intro video).

  • adapter.surface_emul
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Menus and screens → "Show video panels".
  • Source: patches/settings.py

Video panels that an Android media player draws into (XR_KHR_android_surface_swapchain, for example I Am Monkey's intro video), which the Frame's runtime refuses, get an Android Surface from FrameBridge: each video frame is copied into an ordinary swapchain the panel shows. Without it these panels are missing and a game waiting for its video stays black. 0 = leave them to the runtime.

#Native video surfaces (Batman renderer)

Shows Batman: Arkham Shadow's cutscenes; set by that game's recipe.

  • adapter.surface_native
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Not in the Game settings dialog (set by a recipe or the CLI).
  • Catalog games (1): Batman: Arkham Shadow.
  • Source: patches/settings.py

Plays the game's Android video surface through GPU-shared buffers and composes it as a stereo panorama (Batman: Arkham Shadow's cutscenes, see docs/SURFACE_VIDEO.md). Specific to that game's renderer: set by its recipe, not shown in Game settings. Use with frame.hw_video_decode.

#Swap eyes

Shows each eye's picture to the other eye. For testing.

  • adapter.swap_eyes
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Swap eyes" (advanced).
  • Source: patches/settings.py

Swap left/right views (diagnostic).

#Retry refused picture formats

Lets OpenGL ES games start when the Frame refuses their picture format. Leave it on.

  • adapter.swapchain_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 1.
    • Game settings → Troubleshooting → "Retry refused picture formats" (advanced).
  • Suggested by launch-test signatures:
    • swapchain-format (error): The Frame rejected the game's image format.
  • Source: patches/settings.py

Retry rejected GLES formats/MSAA with sRGB, samples=1.

#Steady controller input after focus

For games that crash right after you return to them (for example after the Steam menu).

  • adapter.sync_guard
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Steady controller input after focus" (advanced).
  • Catalog games (2): Batman: Arkham Shadow, Myst.
  • Suggested by launch-test signatures:
    • runtime-input-crash (fatal): The Frame's runtime crashed in its controller code, usually right after the game got focus. sync_guard runs input syncs (xrSyncActions) one at a time and pauses them briefly after focus returns.
  • Source: patches/settings.py

Runs xrSyncActions one at a time with xrPollEvent and skips it for 250 ms after focus returns. For games that crash in the runtime's input code right after focus comes back (SIGSEGV in vrclient.so UpdateActionStateInternal / xrSyncActions, for example Myst).

#Hide Vulkan foveation

For Unreal Engine 5 games that crash on the Frame (for example Metro Awakening).

  • adapter.vk_hide_fdm
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Hide Vulkan foveation" (advanced).
  • Catalog games (1): Metro Awakening.
  • Suggested by launch-test signatures:
    • unreal-fdm-missing (warning): The game will likely crash a few seconds in: Unreal expects foveation data the Frame doesn't provide.
    • unreal-vulkan-driver-crash (fatal): The Frame's Vulkan driver crashed on a call from Unreal.
  • Source: patches/settings.py

Vulkan shim (frame.vk_sanitize): the game doesn't see VK_EXT_fragment_density_map(2). Unreal Engine 5 turns on fragment-density-map foveation when the driver offers it and expects the density map from the headset, which the Frame doesn't provide: image views and barriers for a missing image, then a crash in the Frame's Vulkan driver (for example Metro Awakening). Valve's own foveation layer isn't affected.

#Stop objects popping in and out

For Vulkan games whose models flicker or vanish while you look at them (for example Into The Radius 2). Needs a rebuild.

  • adapter.vk_query_slots · revision 3
  • Changes: Game setting, stored in the build: needs a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Stop objects popping in and out" (advanced).
  • Source: patches/settings.py

Vulkan shim (frame.vk_sanitize): on gives every occlusion query room for both eyes. In multiview passes the Frame's driver writes a zero result for the second eye into the next query, so engines that count on one slot cull visible objects (models popping in and out, for example Into The Radius 2). 0 = off, 1 = on (2 slots).

#Vulkan shader dump (diagnostics)

Saves the game's shaders to find one that hangs the GPU. No effect on the game.

  • adapter.vk_shader_dump
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Vulkan shader dump (diagnostics)" (advanced).
  • Suggested by launch-test signatures:
    • gpu-hang (fatal): The Frame's GPU hung while the game ran (the kernel reset it; the game froze or closed).
  • Source: patches/settings.py

Vulkan shim (frame.vk_sanitize): writes every distinct SPIR-V module the game creates to Android/data/<package>/files/fp_vk_shaders/<size>_<sha256>.spv, with index.txt listing every creation in order with its time, to find the shader behind a GPU hang and capture it for a new vk_shader_fix. Diagnostics include the newest modules. No effect on the game.

#Vulkan shader fixes

Corrects specific shaders that hang the game on the Frame. Comes from a game's recipe.

  • adapter.vk_shader_fix · revision 2
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: str, default empty.
    • Not in the Game settings dialog (set by a recipe or the CLI).
  • Catalog games (1): VR4.
  • Source: patches/settings.py

Vulkan shim (frame.vk_sanitize): SPIR-V modules matching size + SHA-256 get words inserted at a byte offset, for example stores that initialize locals a shader reads before writing (an undefined loop counter hung the GPU in VR4's campaign). Format: <size>:<sha256>:<byte offset>:<word>,<word>,...; several separated by ';'. Comes from a game's recipe.

#Fix depth flicker (Unreal Vulkan)

For Unreal games whose models flicker or show through walls and windows on the Frame (for example Into The Radius 2). Needs a rebuild.

  • adapter.vk_spec_fixes · revision 2
  • Changes: Game setting, stored in the build: needs a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Fix depth flicker (Unreal Vulkan)" (advanced).
  • Catalog games (2): Into The Radius 2, Metro Awakening.
  • Suggested by launch-test signatures:
    • unreal-vulkan-driver-crash (fatal): The Frame's Vulkan driver crashed on a call from Unreal.
  • Source: patches/settings.py

Vulkan shim (frame.vk_sanitize): makes two Unreal habits valid Vulkan - depth images get VK_IMAGE_USAGE_TRANSFER_DST_BIT (they are cleared with vkCmdClearDepthStencilImage) and Qualcomm shader-resolve subpasses lose an invalid depth resolve. Found with the validation layer in Into The Radius 2 (flickering models, windows behind models). Also leaves out image barriers without an image and refuses image views without one, which crash the Frame's driver (for example Metro Awakening).

#Vulkan error checks (log)

Logs Vulkan mistakes the game makes. Needs a special test build.

  • adapter.vk_validation
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "Vulkan error checks (log)" (advanced).
  • Source: patches/settings.py

Diagnostics: the Vulkan shim (frame.vk_sanitize) adds Khronos' validation layer to the game's instance; its findings go to launch.log. The layer library (libVkLayer_khronos_validation.so) must be in the APK.

#OpenGL ES shader dump (diagnostics)

Saves the game's shaders to capture one for a fix. No effect on the game.

  • adapter.zink_shader_dump
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: int, default 0.
    • Game settings → Troubleshooting → "OpenGL ES shader dump (diagnostics)" (advanced).
  • Suggested by launch-test signatures:
    • gpu-hang (fatal): The Frame's GPU hung while the game ran (the kernel reset it; the game froze or closed).
    • zink-shader-fix-mismatch (warning): The game's OpenGL ES shader fix (zink_shader_fix) no longer matches the shader the Frame's GL driver (Zink) builds - a Frame or Lepton update changed the driver's output - so the shader it fixes (for example Vader Immortal's lightspeed jump) may hang the GPU again.
  • Source: patches/settings.py

Shader-fix Vulkan layer (frame.zink_shader_fix): writes every distinct SPIR-V module the GL driver creates to Android/data/<package>/files/fp_spirv/<size>_<sha256>.spv, to capture a shader for a new zink_shader_fix. No effect on the game.

#OpenGL ES shader fixes

Repairs OpenGL ES shaders that hang the graphics chip, from the game's recipe.

  • adapter.zink_shader_fix
  • Changes: Game setting: stored in the build and on the Frame (settings.conf); can be changed without a rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options:
    • Value: str, default empty.
    • Not in the Game settings dialog (set by a recipe or the CLI).
  • Catalog games (1): Vader Immortal: Episode I.
  • Source: patches/settings.py

Shader-fix Vulkan layer (frame.zink_shader_fix) for OpenGL ES games, whose GLSL the Frame's GL driver (Zink) turns into SPIR-V: modules matching size + SHA-256 get words inserted at a byte offset, for example stores that set loop counters and accumulators a shader reads before writing (Vader Immortal's lightspeed jump hung the GPU; found by Klownicle, GitHub #49). Same format as vk_shader_fix. Comes from a game's recipe; the driver's output can change with a Frame update, then the fix no longer matches (logged).

#Files and settings on the Frame

Files, environment and window options written on the Frame when a Quest game or Android app is installed. They don't change the APK.

#Keep the game's saved resolution in step

Keeps the resolution the game saves in step with the headset's picture size (else the picture is shifted, with black borders, after a sharpness change).

  • device.config_sync
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: files: text, default none — path relative to files/ -> {setting name: w | h | expression}
  • Catalog games (1): BlazeRush.
  • Source: patches/settings.py

Some games save their render resolution in a settings file and load it after creating the headset's eye buffers; after a resolution scale change the saved size no longer matches and the picture is displaced or stretched, with black borders (for example BlazeRush's user_config.xml). FramePort writes the values its recipe names into the game's file while the game isn't running (after an install and after a Game settings change), from the Frame's own eye-buffer size times the resolution scale: w and h = the eye buffer's width and height, for example h*16/9. Only existing entries change; the previous file is kept as <file>.frameport-backup. The size is learned from the game's last start, so a file the game wrote before is corrected from the next install or settings change on.

#Show as VR or as a flat window

Choose Flat window if a phone or tablet app shows nothing in the headset, VR if a VR app opens as a flat window.

  • device.display_mode · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: mode: str, default empty — vr or flat (empty = automatic)
  • Source: patches/settings.py

How Lepton runs the app: VR (headless Android, only what the app draws through OpenXR reaches the headset) or a flat window (Lepton's lepton-show-flatscreen marker: the Android window on a screen in the headset, like a phone or tablet app). Automatic uses a flat window for apps without VR code. Choose "Flat window" for a 2D app FramePort took for VR (it shows nothing in the headset), "VR" for a VR app FramePort took for 2D.

#Settings files for the game

Puts settings files next to the game on the Frame, for example to turn off an unsupported effect.

  • device.files · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested (on): CryEngine: variable-rate shading isn't supported on the Frame, so user.cfg turns it off (r_variable_rate_shading = 0; for example The Climb 2).
  • Options: files: text, default none — path relative to files/ -> content
  • Catalog games (2): SUPERHOT VR, The Climb 2.
  • Source: patches/settings.py

Writes config files into the game's Android/data/<package>/files/ on the Frame, to turn off engine features the Frame doesn't support (for example a CryEngine user.cfg with r_variable_rate_shading = 0, as The Climb 2 needs).

#Eye-tracked foveation (Valve)

Try Fixed or Off if one eye shimmers or jitters while menus look fine.

  • device.foveation
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: mode: str, default empty — fixed or off (empty = Valve's default)
  • Source: patches/settings.py

Valve's foveation layer (VALVE_fdm_injection) lowers the image density away from where you look, following each eye's gaze. In some games one eye then shimmers or jitters while menus look fine (the right eye's gaze filter restarts often). "Fixed" keeps the foveation but stops it following the gaze (FDM_DEBUG=disable_offsets); "Off" loads none of Valve's Vulkan layers (VK_INSTANCE_LAYERS=""; costs GPU time in heavy games).

#Hide Android's navigation bar

Hides Android's back, home and recents buttons, which cover the app's own buttons.

  • device.hide_navbar · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested (on): 2D app: Android's navigation buttons would cover the app's own controls.
  • Source: patches/settings.py

Removes Android's back/home/recents buttons from a 2D app's window, where they cover the app's own controls. Turn it off for an app that needs the on-screen back button.

#Extra Lepton settings

Extra settings for the Android container (for testing).

  • device.lepton_env · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: env: text, default none — NAME -> value
  • Catalog games (3): Into The Radius 2, Metro Awakening, QuestCraft.
  • Source: patches/settings.py

Environment variables exported by the launcher (for example VK_INSTANCE_LAYERS="" to test without Valve's layers).

#Controllers as a gamepad (Steam Input)

Lets the game use your controllers as a gamepad instead of a pointer, for 2D games with touch controls (for example SDL games).

  • device.steam_gamepad · also for 2D apps
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested (on): 2D app that declares gamepad support (android.hardware.gamepad or Android TV's launcher): pass the controllers to it as a gamepad.
  • Source: patches/settings.py

Lepton's Android only gets a keyboard, a pointer and touch from the Frame, so a 2D game never sees a controller (the controllers only move the pointer; SDL games show their touch controls). This passes Steam Input's virtual gamepad ("Microsoft X-Box 360 pad", made by Steam for the Frame's controllers and paired Bluetooth pads) into this app's container with an Xbox 360 key layout, and tells SDL games to use it (SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD). Steam Input must be on for the game's shortcut; the controllers must be on when the game starts (a pad Steam makes later isn't seen until the next start). The APK isn't changed. Off for one start: FRAMEPORT_NO_GAMEPAD=1 in the game's launch options.

#Show the app's Android window (for typing)

Lets typing reach this app from Steam's on-screen keyboard or your PC's keyboard. VR keeps working.

  • device.text_input_window
  • Changes: Install only: written on the Frame when the game is installed; the APK isn't changed.
  • Suggested (on): App with text fields: key presses only reach a shown Android window.
  • Catalog games (55): AgeOfJoy, AllInOneSports, Ancient_Dungeon, Audica, Beat Saber, Beat Saber (co-existence build), Blade & Sorcery: Nomad, BodyCombat and 47 more.
  • Source: patches/settings.py

Lepton runs VR apps headless: their Android window is never shown, so it never gets keyboard focus and no key press (Steam's on-screen keyboard, a USB/Bluetooth keyboard, Type on Frame) reaches the app's text fields. With Lepton's lepton-show-flatscreen marker the window is shown (behind the VR view, which keeps working) and Steam's keyboard opens for a selected text field. Steam lists the shown window as "Gamescope" (the Frame's compositor). Pairs with "Make Unity text fields work without a system keyboard".

#PC VR (Proton and Revive)

Options for PC VR games, which run through Proton on the Frame (or Revive on this PC).

#Launch options (SteamVR or OpenXR)

Starts the game with options, for example to choose SteamVR or OpenXR.

  • pcvr.launch_args
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested (on): Selects SteamVR/OpenXR (…).
  • Options: args: str, default empty — arguments, for example -hmd=OpenXR
  • Catalog games (2): Eleven: Table Tennis VR (PC VR), SUPERHOT VR (PC VR).
  • Suggested by launch-test signatures:
    • unity-vr-init (error): The game's Unity log shows that a VR device failed to start.
  • Source: patches/pcvr.py

Command-line arguments for the game program. Games that support several VR runtimes pick one with an argument, for example Unreal's -hmd=OpenXR or -hmd=SteamVR, Unity's -vrmode OpenVR, or a game's own switch (-Runtime=OpenXRHMD). FramePort fills them in from the game files (the repack's VD.bat with the Oculus module swapped for OpenXR, else the engine's usual switch).

#Provide the Oculus runtime from Revive (Frame)

Points Oculus games at Revive on the Frame.

  • pcvr.libovr_redirect
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Offered (off): Supports SteamVR/OpenXR itself: no Oculus runtime needed.
  • Suggested (on): Lets the game find Revive's runtime on the Frame (doesn't bypass its signature check).
  • Source: patches/pcvr.py

On the Frame, place Revive's runtime (FramePort's Revive, or the repack's bundled LibRevive) where the game's Oculus SDK looks for LibOVRRT so it can load a VR runtime (pure runtime substitution — what Revive's LoadLibrary hook does on Windows; that hook doesn't work under Proton on the Frame). It does NOT bypass the Oculus runtime signature check: a game that verifies the runtime's signature will still refuse it. Ignored on this PC (Revive's hook handles it there).

#No Unreal crash reporter

Stops Unreal's crash reporter, which can block the game from starting.

  • pcvr.no_crash_reporter
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested (on): Unreal game: close on a crash instead of showing the crash reporter.
  • Suggested by launch-test signatures:
    • unreal-crash (fatal): The game crashed (Unreal's crash reporter started).
  • Source: patches/pcvr.py

Unreal games start CrashReportClient when they crash, which leaves a crash dialog instead of simply closing. This passes -nocrashreports to the game and, on the Frame, renames the game's copy of CrashReportClient.exe so it can't start (your game files on this PC aren't changed).

#Patch Oculus detection for Unreal (Frame)

Lets Unreal games accept a headset that isn't an Oculus Rift.

  • pcvr.oculus_unreal
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Offered (off): Uses SteamVR/OpenXR, not its Oculus plugin.
  • Suggested (on): Unreal game: its Oculus plugin checks for the Oculus service before it starts VR.
  • Suggested by launch-test signatures:
    • oculus-hmd-event (error): The game runs as a flat window because FramePort's Oculus detection helper failed.
  • Source: patches/pcvr.py

The PC VR counterpart of OVRPort's 'Patch Oculus detection for Unreal'. Unreal's Oculus plugin only starts when the Oculus service announces a headset (the Windows event 'OculusHMDConnected'); without it the game runs as a flat window. On the Frame the launcher runs the game through FramePort's small helper (fp_oculushmd.exe) that provides that event while the game runs, instead of relying only on Revive's hook of the check. Ignored on this PC (the Oculus app or Revive handle it there).

#Extra Proton settings (Frame)

Extra settings for Proton (for testing).

  • pcvr.proton_env
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: env: text, default empty — KEY=value lines
  • Source: patches/pcvr.py

Environment variables for the Proton launcher on the Frame (for example DXVK_HUD=fps), one KEY=value per line.

#Proton debug log (Frame)

Writes a detailed Proton log for troubleshooting.

  • pcvr.proton_log
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Suggested by launch-test signatures:
    • dxvk-device-lost (fatal): The GPU stopped responding while running the game (D3D through DXVK on freedreno).
    • oculus-hmd-event (error): The game runs as a flat window because FramePort's Oculus detection helper failed.
    • unity-crash (fatal): The game crashed (Unity's crash handler wrote a report; the Unity log in the launch log shows the stack).
    • unreal-crash (fatal): The game crashed (Unreal's crash reporter started).
    • wine-crash (error): The game crashed under Wine/Proton.
  • Source: patches/pcvr.py

Write Proton's log (PROTON_LOG=1) to steam-<appid>.log in the game folder on the Frame. Slower; use while debugging a game that doesn't start.

#Proton version (Frame)

Which Proton runs the game on the Frame. Stable is smoother; try Experimental if the game doesn't start or runs badly.

  • pcvr.proton_tool
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: tool: str, default empty — proton-stable (default), proton-experimental, or a compat tool name
  • Source: patches/pcvr.py

Which Proton build runs the game on the Frame: the stable Proton (the default: smoother in our tests) or Proton Experimental (gets Valve's ARM64 fixes first; try it when a game doesn't start or runs badly). Also takes any compat tool name from the Frame's ARM64 list.

#Use the repack's launcher (bundled Revive)

Starts the game with the launcher that came with your copy.

  • pcvr.repack_launcher
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested (on): The game folder has its own Revive and loader (…): run the game directly.
  • Conflicts with: pcvr.revive
  • Options: dlls: str, default empty — loader DLLs next to the exe (comma-separated)
  • Source: patches/pcvr.py

Some game folders are already set up for SteamVR: a Revive copy (LibRevive64.dll) next to the game, started by a small loader DLL (for example xinput1_3.dll) that Windows loads from the game's folder. Then FramePort starts the game program directly — like double-clicking it — instead of through its own Revive (two Revives conflict; for example the Oculus Platform check then fails). On the Frame, Wine is told to use those loader DLLs from the game folder instead of its own.

#Revive (Oculus LibOVR → OpenXR)

Lets games made for Oculus PCs run on SteamVR.

  • pcvr.revive
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Offered (off): The game folder already has its own Revive set up (see 'Use the repack's launcher'); a second Revive breaks it.
  • Offered (off): Supports SteamVR/OpenXR itself: SteamVR / the Frame run it directly.
  • Suggested (on): Oculus/LibOVR game: Revive translates it to SteamVR/OpenXR (without it it runs flat).
  • Conflicts with: pcvr.repack_launcher
  • Suggested by launch-test signatures:
    • unreal-crash (fatal): The game crashed (Unreal's crash reporter started).
  • Source: patches/pcvr.py

Launch the game through Revive's injector, which translates the Oculus PC SDK (LibOVR) to OpenXR. Needed by every Oculus Rift game that isn't OpenXR-native. FramePort downloads Revive itself.

#Revive: SteamVR (OpenVR) backend on PC

On this PC, runs Revive through SteamVR (works with more headsets).

  • pcvr.revive_openvr
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Offered (off): Not launched through FramePort's Revive.
  • Suggested (on): PC: Revive's SteamVR/OpenVR backend is the most reliable path.
  • Requires: pcvr.revive
  • Suggested by launch-test signatures:
    • openxr-missing-ext (fatal): The VR runtime lacks a feature Revive needs (XR_KHR_D3D11_enable or win32 time conversion).
  • Source: patches/pcvr.py

On this PC, launch the game through Revive's OpenVR backend, which talks straight to SteamVR — the original, most reliable Revive path. On by default for PC installs. Turn it off to use Revive's newer OpenXR backend instead. Ignored on the Frame (which always uses OpenXR).

#Automatic SteamVR performance settings (this PC)

Picks a refresh rate and motion smoothing that suit the game on this PC.

  • pcvr.steamvr_tuning
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested (on): Adjusts the refresh rate / motion smoothing when the game can't keep up.
  • Options:
    • refresh: float, default 0.0, 0–144 — refresh rate in Hz (0 = automatic)
    • smoothing: str, default auto — motion smoothing: auto, on, off, always or global
  • Catalog games (4): Beat Saber (PC VR), Eleven: Table Tennis VR (PC VR), Pistol Whip (PC VR), SUPERHOT VR (PC VR).
  • Source: patches/pcvr.py

Before each Play on this PC, FramePort reads SteamVR's record of the game's last session (frames dropped; frame times from fpsVR if installed). If it dropped frames, it lowers the game's refresh rate to one whose frame budget fits (for example 96 → 90 Hz) and turns motion smoothing on, through SteamVR's per-application settings; each later session can step down again. Set a refresh rate or smoothing mode here to choose yourself. Ignored on the Frame.

#SteamVR overlay app (Frame)

Lets SteamVR on the Frame show this overlay app over your games (and start it with SteamVR).

  • pcvr.vr_overlay
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested: not automatically; set on the game page (Customize), by a recipe or after a launch test.
  • Options: autostart: bool, default True — start with SteamVR
  • Source: patches/pcvr.py

For overlay apps (fpsVR, wrist watches and other SteamVR add-ons that draw over games instead of being a game): FramePort registers the app with the Frame's SteamVR, which draws its overlays over whatever you play there, Quest and PC VR games alike. With 'start with SteamVR' on, SteamVR starts it by itself (also after a restart); otherwise start it from the library. It isn't launch-tested (it shows nothing without a game). Ignored on this PC.

#Frame OpenXR compatibility layer

Lets games written for newer OpenXR versions run on the Frame.

  • pcvr.xr_timefix
  • Changes: Applied when the PC VR game is installed or started; no rebuild.
  • Suggested (on): The Frame's OpenXR runtime rejects Proton's OpenXR 1.1 request without it.
  • Catalog games (5): Beat Saber (PC VR), Eleven: Table Tennis VR (PC VR), Pistol Whip (PC VR), Rick and Morty: Virtual Rick-ality (PC VR), SUPERHOT VR (PC VR).
  • Suggested by launch-test signatures:
    • openxr-api-version (fatal): The game got no VR, so it runs as a flat window or Revive fails.
    • openxr-missing-ext (fatal): The VR runtime lacks a feature Revive needs (XR_KHR_D3D11_enable or win32 time conversion).
    • openxr-time-conversion (error): The VR runtime refused a time conversion that Proton needs for Windows games' performance-counter times.
  • Source: patches/pcvr.py

Loads FramePort's OpenXR layer under Proton on the Frame. The Frame's SteamVR runtime only accepts OpenXR 1.0 apps, but Proton's VR helper asks for 1.1, so without the layer VR never starts (the game shows as a flat window, or Revive fails with 'Unable to load LibOVRRT DLL'); the layer retries as 1.0. It also emulates xrConvertTimespecTimeToTimeKHR if a runtime refuses it. Ignored on this PC.