Compare commits

...
367 Commits
Author SHA1 Message Date
spoopyghosty0 8167cb86c6 Merge the shared hardware video decoder (PR #128, adapted: per game, off switch, VP9 fixes)
# Conflicts:
#	agent/frameport_agent.py
2026-10-10 02:25:41 -04:00
spoopyghosty0 44bc689348 Shared video decoder (codec revision 8): hidden VP9 frames no longer end the EOS drain early
Iris returns an empty capture buffer (bytesused 0, no LAST flag, time 0) for every VP9 frame that isn't shown
(alt-ref frames split from superframes). FFmpeg's V4L2 wrapper takes any empty capture buffer during a drain
for the end of the stream, so the first hidden frame decoded after EOS ended it and the pictures still in the
driver were lost (two-pass VP9 4K: 573/600 and 617/640, always the last frames); outside a drain the empty
buffers were returned as pictures, which the component then guessed away by counting hidden frames.
build.py now patches v4l2_context.c to requeue empty capture buffers without LAST/ERROR; the drain ends at the
LAST buffer, or after a skipped empty buffer at one silent second, so it can't block. The component's
hidden-frame counting is removed. Dev Frame (Batman's container): two-pass VP9 4K 600/600 and 640/640 in
hardware with the same Y hashes as OMX.google.vp9.decoder (seek phase too), VP9 without hidden frames,
H.264 4K and HEVC 4K 600/600, VP9 surface output 600/600. Two builds (different dirs and NDK copies) give the
same libstagefrighthw.so 141de01f.
2026-10-10 02:22:48 -04:00
spoopyghosty0 007db344d7 Shared video decoder: remove a game's old per-game codec folder once its launcher is converted, also when the recipe (not deployment.json) asks for hardware decoding (seen with Batman on the dev Frame) 2026-10-10 01:01:33 -04:00
spoopyghosty0 3fb2621030 Shared video decoder: per game (frame.hw_video_decode) with a global off switch; 8K retry at start and VP9 fixes from the hw-video-decode branch
- Opt-in per game: only launchers of games whose recipe has frame.hw_video_decode (install stage, no APK change;
  suggested from analysis media_codec, ANALYSIS_VERSION 8) get the codec line (deployment.json hw_video_decode,
  finalize + upgrade_launchers). Games that had agent 70's per-game codec (Batman) keep it; their old
  <base>/frameport-codec folders are removed afterwards. Batman: catalog + migration batman_video_patches
  (frame.hw_video_decode + the hidden adapter setting surface_native, no more package check); 4XVR catalog.
- Off switch: Settings -> Installing "Hardware video decoding" (library video.hw_decode, default on) -> agent
  video_codec_switch (video-codec/disabled, checked by the launcher line and the wrapper); FRAMEPORT_NO_HW_VIDEO=1
  for one game.
- Connection: the codec is checked once per connection, also after a failed install; a Frame keeps the same or a
  newer revision built elsewhere (logged) instead of flip-flopping between PCs.
- Wrapper: the merged media_codecs.xml goes to $XDG_RUNTIME_DIR/frameport-video, never into the version directory.
- Decoder: refused (busy) Iris sessions retry until 20 s after the plugin loaded (SteamVR's link holds a session
  ~12 s at game start), else 2 s, before the software fallback; VP9 capped at 4096x2304 (XML + component, larger
  decodes in software); hidden VP9 frames' pictures dropped. Manifest revision 7.
- build.py builds from paths with spaces and from freshly extracted FFmpeg sources. Artifacts rebuilt here, identical
  from two trees (ext4 and the NTFS repo path, two NDK copies); PR #128's own sources rebuild to its binary.
- AGENT_VERSION 71 (matches the connection's gate); triage hw-video-decoder-busy, PLAYBOOK row, docs.
2026-10-10 00:58:24 -04:00
spoopyghosty0 39ca9a5f0d Catalog: Audica works (shared working config)
Closes #126
2026-10-10 00:28:39 -04:00
spoopyghosty0 e64e8a95e0 Uninstall dialog: option to also delete the game's saves and everything it stored on the Frame (mods, downloads); they survived every uninstall before (GitHub #130) 2026-10-10 00:28:37 -04:00
spoopyghosty0 69e888c7fe Install on this PC works on Windows again: the agent (loaded for its VDF code) imported the POSIX-only fcntl at the top (ModuleNotFoundError for every PC VR install; GitHub #131) 2026-10-10 00:28:36 -04:00
spoopyghosty0 ce809c432d Merge PR #128: shared hardware video decoding (Lucas-Mathieu) 2026-10-10 00:23:42 -04:00
Lucas-Mathieu 26cee1551e Deploy shared hardware video decoding for compatible Lepton apps 2026-10-10 03:36:56 +02:00
spoopyghosty0 f812ea8716 Codec wrapper (PR #96): find the host's podman when Lepton calls it with the Android guest's PATH (its boot-wait, app-pid and logcat-mirror podman exec calls failed, so launch.log lost logcat and the container could be stopped early) 2026-10-09 17:54:44 -04:00
spoopyghosty0 3dc0a95379 Catalog: Doom3Quest uses frame.gl_multiview_fbo (HUD/PDA shown, no frame-rate drop: Xandrix1987's headset test, GitHub #77) 2026-10-09 16:30:33 -04:00
spoopyghosty0 f8244f582d Catalog: cubism works (shared working config)
Closes #121
2026-10-09 16:29:36 -04:00
spoopyghosty0 69fbdfdc4a SUPERHOT VR (Quest): create its cloud save folder at install, so the launcher gives it group write permission before the very first start (the game creates and checks it in the same millisecond; GitHub #120); triage text says to start again 2026-10-09 16:29:34 -04:00
spoopyghosty0 ef3272a31b Catalog: Vader Immortal III's campaign intro starts black by design (owner) 2026-10-09 15:04:18 -04:00
spoopyghosty0 b0f3ef2698 Catalog: Vader Immortal Episodes II and III work (owner's headset test) with Episode I's Unreal fixes (quest precompile, key map, thumb touch, pose_time_fix), all found in their code by the heuristics 2026-10-09 14:37:11 -04:00
spoopyghosty0 1711e7f7d9 Docs: session triage (PLAYBOOK rows for the session findings, CLAUDE.md note incl. the pac_hints survey) 2026-10-09 14:22:22 -04:00
spoopyghosty0 ff6cdf3b6a Triage real play sessions: the connection refresh fetches a finished session's log (agent v70) and triages it (launch-test signatures + new space-warp-used question and gpu-hang, find_rp_state for unreal-msrtt-crash, slow-frames from FrameBridge pacing, focus-dips), stored as last_session; game page "Last session" callout; value suggestions (adapter.key=value); FrameBridge-only fixes applied live via set_settings; CLI frameport session [--apply] 2026-10-09 14:22:20 -04:00
spoopyghosty0 28517a1999 Agent v70: session_log (the newest play session's launch.log sliced to 4 MB + its crash logcat + kernel GPU hang lines), last_play in list_installed, launch tests mark their session in plays.log 2026-10-09 14:22:17 -04:00
spoopyghosty0 af9c207ddf FrameBridge: always log the runtime's focus losses and returns with their length (focus: lost / back after N ms), before focus_hold hides a dip; for session triage 2026-10-09 14:03:23 -04:00
spoopyghosty0 88045bcf4e Merge remote-tracking branch 'origin/main' into merge/pr96 2026-10-09 13:43:24 -04:00
spoopyghosty0 5147710fad Merge Batman cutscene playback (hardware HEVC decoding, stereo composition) by Lucas-Mathieu (GitHub #96)
Adapter rebuilt here; the codec plugin rebuilt here with native/hevc/build.py (NDK r27c, Lepton SoftOMX fingerprint 456e912c) is byte-identical to the contributed one (c1c2a73e). Agent version 70 -> 69 (main was at 68).
2026-10-09 13:43:22 -04:00
spoopyghosty0 9c45cff09a Heuristics: suggest pose_time_fix for Unreal 4 games with Vader Immortal's Oculus input (the unreal_thumb_touch code match). Catalog: Phantom, Robo Recall and Time Stall get frame.unreal_thumb_touch + pose_time_fix (their code matches Vader's; not yet checked in these games), Star Wars: Tales gets frame.unreal_thumb_touch instead of proximity_emul (as Vader) 2026-10-09 13:43:07 -04:00
Lucas-Mathieu b4848c0424 Harden codec deployment and isolate native video hooks 2026-10-09 19:24:51 +02:00
spoopyghosty0 3a46b78361 Catalog: Clockwork (Quest), Beat Saber, Eleven: Table Tennis VR and Pistol Whip (PC VR, run directly without Revive) from shared working configs
Closes #116, closes #117, closes #118, closes #119
2026-10-09 13:21:50 -04:00
spoopyghosty0 75bbc6eb5f Heuristics: suggest scene_emul for every game that declares Meta's USE_SCENE permission, not only mixed-reality-only ones (VR HOT's room setup retried forever: LoadSceneModel failed / no XR_FB_spatial_entity_query; with scene_emul the room setup returned without errors). Catalog recipes still win (6 verified games declare USE_SCENE and run without it) 2026-10-09 13:06:44 -04:00
Lucas-Mathieu da638aea99 Merge remote-tracking branch 'origin/main' into fix/batman-cutscene-playback
# Conflicts:
#	agent/frameport_agent.py
#	artifacts/SHA256SUMS
#	artifacts/arm64-v8a/libopenxr_loader_generic.so
#	artifacts/armeabi-v7a/libopenxr_loader_generic.so
#	native/adapter/frame_adapter.c
2026-10-09 18:29:12 +02:00
spoopyghosty0 7c37b479db Agent v68: launch tests count their window from Lepton's 'Waiting for app' (up to 240 s more for boot + install). The first start after an APK change installs the app first; a 45 s window from the launcher stopped the container mid-install and left a broken installed APK ('base.apk is not zip') that never started again (VR HOT) 2026-10-09 11:58:54 -04:00
spoopyghosty0 fa473c5ada frame.unreal_thumb_touch: UE4 OculusInput's ThumbUp from the capacitive touches instead of near-touch, which the Frame never reports (thumbs always pointed up). Three instructions in SendControllerEvents (masks 0x2/0x8 -> 0x0f00/0x000f, NearTouches load -> Touches), matched exactly; suggested where the code matches (analysis unreal_thumb_touch, ANALYSIS_VERSION 7): Vader Immortal Ep. I, Robo Recall, Phantom: Covert Ops, Time Stall, Star Wars: Tales. Vader's recipe uses it instead of proximity_emul (the binding didn't animate the thumbs). Found by Klownicle, GitHub #49 2026-10-09 11:35:36 -04:00
spoopyghosty0 1e6ce04e4f pose_time_fix: never move a recent predicted display time; monotonic times only told apart when the clocks are more than 4 display periods apart and the time is clearly nearer the monotonic now (GitHub #49: on a Frame with XrTime only ~68 ms ahead of CLOCK_MONOTONIC, a request at the frame's display time after a hitch was taken for a monotonic time and moved +67.7 ms). Found by Klownicle, GitHub #49 2026-10-09 11:35:35 -04:00
spoopyghosty0 5cd5b119e7 Lint: extraneous parentheses (ruff UP034) 2026-10-09 11:33:00 -04:00
spoopyghosty0 186138cc3c Game page: a patch the build left out because the OVRPort runtime already has the fix (build.superseded, e.g. haptic_fix with runtime 3.4.3-aa54c3f) no longer counts as a settings change: 'Update on Frame' stayed after every update (owner's VR HOT, Klownicle's Vader, GitHub #49) 2026-10-09 11:32:40 -04:00
spoopyghosty0 98c7ca980a Triage: Lepton's own short lines survive the game-process filter. With the package known, game_lines dropped every line of 3 words or fewer, so Lepton's 'Boot complete!' vanished and the transient 'is not a running context' failed launch tests in the GUI although the games ran (owner's runs: Come Closer, AntiZeroGames CH, SKYBOX; Klownicle's Vader, GitHub #49). Only logcat lines are filtered by pid now 2026-10-09 11:29:12 -04:00
spoopyghosty0 b2470b962a Catalog: Max Mustard is listed by its name, not its package name Matilda (GitHub #110) 2026-10-09 11:10:09 -04:00
spoopyghosty0 2a705bc6d1 frame.gl_multiview_fbo: single-view twins for multiview programs drawn into flat framebuffers (GitHub #77)
Mesa enforces OVR_multiview's rule that a draw's program declares as many views as the draw framebuffer has and drops the draw silently; Doom3Quest compiles every vertex shader with layout(num_views=2) and draws its HUD/PDA into 2D-texture FBOs, which stay black on the Frame.

native/glmv (libfpglmv.so, same length as libGLESv3.so): the engine library's dlopen string is rewritten to it and it becomes the first DT_NEEDED. It records stage sources at link time and, when a multiview program draws into a framebuffer without views, draws with a lazily built single-view twin (num_views layout blanked, gl_ViewID_OVR -> 0u; attribute locations, block bindings and uniform values copied), then rebinds the original. Opt-in and experimental (analysis gl_multiview_libs, ANALYSIS_VERSION 6), setting gl_mv_debug, triage gl-multiview-twin-failed.

Host tests: the rewriter on Doom3Quest's 19 shaders (GPL-3.0 fixtures) and glmv.c against a stand-in GL that applies Mesa's rule. Untested on the device.
2026-10-09 10:54:40 -04:00
spoopyghosty0 5d44831757 Agent v67: keep launch.log filling when Lepton's logcat mirror dies ('logcat: Unexpected EOF!' right after the game starts, about 1 launch in 50: Vader Immortal on Lepton 3.0.5, Under Cover on 2.8.14). launch.sh starts _logcat_keeper, which then reads the container's logcat itself (podman exec ... logcat -T 2000, up to 5 restarts) so the dashboard auto-hide and launch tests see the game; upgrade_launchers adds it to existing launchers 2026-10-09 10:14:57 -04:00
spoopyghosty0 456880501b PC VR: a catalog recipe verified with another build (different VR APIs) keeps the build's own launch arguments; Electron launchers rank below the game; agent v67 collects Unity's Player.log / output_log.txt / crash error.log for launch tests and diagnostics; triage unity-vr-init and unity-crash (GitHub #105) 2026-10-09 10:10:33 -04:00
spoopyghosty0 63f7ae12e1 Catalog: Vader Immortal: Episode I works (owner's headset test of the GitHub #49 fixes by Klownicle) 2026-10-09 10:06:44 -04:00
spoopyghosty0 fa69ffefd2 Vader Immortal: loading card, controls, lightspeed shaders, thumbs (GitHub #49)
Klownicle's five fixes for Vader Immortal: Episode I, reimplemented as FramePort patches (found by Klownicle,
GitHub #49; their prebuilt APK is not used):

- frame.unreal_quest_precompile: UVRUtils::GetQuestShaderPrecompilePercent returned 0.0 on its non-Quest branch, so
  the menu waited forever on the loading card; that branch now returns 1.0. Located by symbol, every instruction
  around it checked (bl IsRunningOnSantaCruz; tbz w0,#0; fmov s0,wzr; ldp; ret); other builds stay untouched.
- frame.unreal_quest_keymap: the RPOC key selector (shared by AddAxisMapping and AddActionMapping, so both mapping
  kinds were affected) picked the empty Gear VR key set for an Oculus HMD; the tbz to it becomes a nop. Located as
  the common callee of both functions, pattern-checked.
- frame.zink_shader_fix + native/zinkfix (libVkLayer_fp_shaderfix.so): a Vulkan layer under Zink for GLES games
  that applies zink_shader_fix entries (vk_shader_fix format) to the SPIR-V Zink generates; it adds itself to
  GraphicsEnv's debug layer list from a constructor (the engine library loads it first). zink_shader_dump=1
  captures modules. Vader's recipe carries the two lightspeed-shader fixes (12 OpStores each).
- adapter proximity_emul (FrameBridge): OVRPlugin's thumb/index proximity actions get bindings to the capacitive
  touch inputs when the runtime lacks XR_FB_touch_controller_proximity (OVRPort offers the extension anyway):
  generic replacement for the libUE4 ThumbUp patch.
- Vader's recipe: pose_time_fix + proximity_emul, status unknown (to test in the headset), min_app 0.12.1.

Analysis records unreal_quest_gates (ANALYSIS_VERSION 4). Star Wars: Tales from the Galaxy's Edge (same studio)
has neither gate (different engine build) and gets a catalog entry with pose_time_fix + proximity_emul.

Headless on the dev Frame (Lepton 3.0.5): the layer loads into Zink's instances, the proximity bindings are
accepted, and the game passes the loading card to the "guardian smaller than recommended, press any button" screen.
2026-10-09 09:20:15 -04:00
spoopyghosty0 f78bc82cc4 frame.vivox_audio_route: Vivox voice chat without Android 12 audio routing (GitHub #101)
Newer Vivox builds (Green Hell VR) call AudioManager communication-device methods (API 31) from com.vivox.sdk.AudioChangeListener without a version check; Lepton is Android 11 -> NoSuchMethodError. The methods that call them now return at once (in-place dex edit, Dex.return_early). Detected by analysis vivox_api31 (ANALYSIS_VERSION 4), triage vivox-api31. Verified headless: Green Hell starts, Vivox initialises, ~65-70 fps.
2026-10-09 09:09:24 -04:00
spoopyghosty0 dfacf6a206 FrameBridge: serve cube swapchains the runtime refuses (GitHub #107)
Budget Cuts Ultimate asks for a 2048x2048 cube swapchain (faces=6); the Frame's runtime has no cube layers and refuses it (-2), OVRPlugin carries on with no images and crashes in ovrp_EndFrame4 (memset). cube_standin (default on, GLES) serves it as a GL cube map in the game's context and drops its layers. Triage cube-swapchain-refused (supersedes unity-render-crash/native-crash). Verified headless: the game runs on at ~70 fps.
2026-10-09 09:09:23 -04:00
spoopyghosty0 b2f14c1e2e Catalog: SUPERHOT VR (Rift) keeps the build's own launch arguments (GitHub #105: the older Oculus + SteamVR build needs -vrmode OpenVR; the catalog recipe from the OpenXR build dropped it) 2026-10-09 08:49:53 -04:00
spoopyghosty0 03d7a311bf Catalog: Batman: Arkham Shadow gets sync_guard to test (GitHub #102: quit to Steam's waiting screen after the Frame runtime crashed in xrSyncActions, the input race Myst had) 2026-10-09 08:32:50 -04:00
spoopyghosty0 cd5119278b Catalog: The Light Brigade (works with issues)
Closes #114
2026-10-09 07:56:14 -04:00
spoopyghosty0 6ab3608a44 Catalog: Gravity Lab (works)
Closes #113
2026-10-09 07:56:06 -04:00
spoopyghosty0 c0539af368 Catalog: Does it Stack? (works with issues)
Closes #112
2026-10-09 07:56:02 -04:00
spoopyghosty0 c6363140f4 Catalog: Walkabout Mini Golf (works)
Closes #111
2026-10-09 07:55:58 -04:00
spoopyghosty0 187105b729 Catalog: Matilda (works)
Closes #110
2026-10-09 07:55:55 -04:00
spoopyghosty0 b983c0f11f Catalog: The Tale of Onogoro (works)
Closes #108
2026-10-09 07:55:52 -04:00
spoopyghosty0 c7cee33889 Catalog: Please Don't Touch Anything (works)
Closes #106
2026-10-09 07:55:49 -04:00
spoopyghosty0 d9d73b8aec Triage: Lepton 3.0.5's transient 'is not a running context' (printed while its container is still starting, then 'Boot complete!') no longer fails a launch test (container-not-started unless Boot complete!; VR4 ran at 72 fps on the dev Frame but was marked failed) 2026-10-09 07:55:24 -04:00
spoopyghosty0 48455b9b72 pose_time_fix: robust clock offset (the largest of the last ~2 s of xrWaitFrame samples; hitches made single samples dip by up to 2.5 s and pushed fixed times up to 2 s into the future), far-past requests located at the frame's display time, nothing moved before 8 samples. Headless survey of 54 games: no other game asks for head/views on the monotonic clock; UE4 OVRPlugin 1.89 games and The Room VR ask for XrTime ~0 every frame and work today, so the setting stays suggested for Unity built-in Oculus games only. BattleSisters on the Frame: every moved request now at 0.0 ms from the display time 2026-10-09 01:35:15 -04:00
spoopyghosty0 af798c0bf3 Catalog: BattleSisters entry parses again (my previous edit put colons into a plain YAML text block); written with catalog.to_yaml 2026-10-08 22:55:47 -04:00
spoopyghosty0 ed714c9d65 Catalog: BattleSisters plays with hands following the controllers (adapter pose_time_fix, owner's headset test) 2026-10-08 22:51:26 -04:00
spoopyghosty0 832b401630 Pose time fix (adapter pose_time_fix, pose_debug): OVRPlugin locates its "now" poses at the monotonic clock
BattleSisters' hands lagged behind the controllers (also with ovrp_hold_physics on or off). pose_debug=1 (new,
FrameBridge: per 5 s and per located space, the requested time minus the predicted display time) showed on the dev
Frame (SteamOS 0.4.5): XrTime runs 2.56 s ahead of CLOCK_MONOTONIC, the hand spaces were located at -2564 ms (the
monotonic "now" passed on as an XrTime: OVRPort's dispatcher converts XR_KHR_convert_timespec_time 1:1 and
FrameBridge's emulation is never asked) and the head at XrTime 0.1 s (~1450 xrLocateViews/xrLocateSpace per 5 s).

pose_time_fix (default off; suggested for Unity built-in OVRPlugin games): in xrLocateSpace(s)/xrLocateViews a time
nearer the monotonic clock than XrTime's "now" is moved by the offset measured at xrWaitFrame, one more than 0.5 s
before the display time goes to "now". Headless with it on: every far-past request moved, located times -9.8..0 ms
from the display time. Host unit test for the time rules; PLAYBOOK row.
2026-10-08 22:41:34 -04:00
spoopyghosty0 114b7cb4d6 Catalog: BONELAB works on 1.2068 and 1.2974 (owner's headset test of frame.slz_vulkan_hooks) 2026-10-08 22:08:29 -04:00
spoopyghosty0 a4d3ce5e00 Merge BONELAB 1.2974 fix by UnicronNL (GitHub #82)
frame.slz_vulkan_hooks: Stress Level Zero's plugin no longer intercepts Unity's Vulkan start-up and samplers (it called an invalid function right after OVRPlugin's pre-init instance was destroyed). Test fixture rebuilt by us, byte-identical. Owner's headset test: BONELAB 1.2974 plays well.

Closes #82

# Conflicts:
#	docs/GAMES.md
#	tests/test_patches.py
#	tests/test_triage.py
2026-10-08 22:07:54 -04:00
spoopyghosty0 b3095b110a Merge Sniper Elite VR fixes by UnicronNL (GitHub #81)
ovrpshim frame-begin gate and held-back physics update (per-game settings ovrp_begin_gate / ovrp_hold_physics, on in Sniper Elite VR's recipe), xrshim PCM vibrations, unity_oculus_check revision 5; artifacts rebuilt by us. Owner's headset test: Sniper Elite VR plays, Accounting+ unchanged, BattleSisters unaffected (settings off).

Closes #81

# Conflicts:
#	artifacts/SHA256SUMS
#	docs/GAMES.md
2026-10-08 22:06:18 -04:00
spoopyghosty0 fb284b6fc4 Catalog: Star Wars Pinball VR (works; frame.unreal_gl_shim + frame.unreal_ovrp_entrypoints + frame.pac_hints, needs FramePort 0.12.1)
Closes #83
2026-10-08 21:56:46 -04:00
spoopyghosty0 c0df52b981 Unpaired pointer-authentication hints (frame.pac_hints, GitHub #83): with VR running, Star Wars Pinball VR died with SIGILL ILL_ILLOPN at an autiasp (*pc=0xd50323bf) on Unreal's HttpManager thread: its libUE4.so has 38 paciasp but 40 autiasp (OpenSSL's Poly1305 NEON assembly). Quest CPUs run PAC hints as NOPs, the Frame's CPU checks them. In a library whose counts differ, every paciasp/autiasp becomes a NOP in place (libraries using retaa/pacibsp forms are left alone). Suggested by the new triage signature pac-unpaired 2026-10-08 21:50:01 -04:00
spoopyghosty0 a1b0a3f350 Unreal OVRPlugin stand-ins (frame.unreal_ovrp_entrypoints, GitHub #83): Unreal's Oculus module dlsyms every ovrp_* function of the OVRPlugin it was built against and ANDs the results; OVRPort's OpenXR OVRPlugin lacks ovrp_GetPTWNear (Star Wars Pinball VR, UE 4.25 / OVRPlugin 1.44), so the wrapper failed, OculusHMD never pre-initialised and the game crashed without an HMD. Analysis records the engine library's ovrp_* names (extra.unreal_ovrp_lookups, ANALYSIS_VERSION 3); the patch compares them with the shipped libOVRPlugin.so and adds a generated libfp_ovrpstubs.so (DT_NEEDED of the plugin: dlsym on its handle searches its dependencies) whose stand-ins return ovrpFailure (stubgen result=). libUE4.so stays byte-identical. Suggested when the newest OVRPort runtime's plugin (tools.overport.runtime_lib) lacks a looked-up name (bundled fallback before a runtime is downloaded) 2026-10-08 21:33:06 -04:00
spoopyghosty0 df864e9fed GL shim keeps Unreal's multiview (GitHub #83): Unreal 4.25 only enables mobile multiview when GL_OVR_multiview, GL_OVR_multiview2 and GL_OVR_multiview_multisampled_render_to_texture are all listed (FOpenGLES::ProcessExtensions), so hiding the last one with gl_hide_msrtt switched multiview off. For Unreal (libUE4.so/libUnreal.so loaded, MSRTT hidden, multiview kept) the shim keeps that extension visible and maps glFramebufferTextureMultisampleMultiviewOVR to the single-sampled glFramebufferTextureMultiviewOVR (log 'multiview multisampled render-to-texture (N samples) drawn single-sampled'). Unity/other engines unchanged. Previous source rebuilt byte-identical before the change 2026-10-08 21:26:30 -04:00
spoopyghosty0 6595a31048 ovrpshim: frame-begin gate and held-back physics update only with the per-game settings ovrp_begin_gate / ovrp_hold_physics (default off; Sniper Elite VR's recipe turns both on). With them BattleSisters' hands lagged and its loading screen stuttered (owner's headset test); Accounting+ was fine. libfp_ovrp.so rebuilt 2026-10-08 21:13:28 -04:00
spoopyghosty0 f4bcb658e1 Unreal GL shim (frame.unreal_gl_shim, GitHub #83): Star Wars Pinball VR crashes ~3 s in with fault addr 0x10000 on the RHIThread in libgallium_dri.so: Unreal's mobile MSAA renders through multisampled render-to-texture and Zink's find_rp_state indexes rendering_state_cache[6] one past its end. The GL shim hides MSRTT (gl_hide_msrtt); it now also keeps multiview for Unreal (libUE4.so/libUnreal.so, like Unity). Offered for Unreal GLES games, suggested by the new triage signature unreal-msrtt-crash, not from the APK alone. Old glshim source rebuilt byte-identical before the change 2026-10-08 20:11:40 -04:00
spoopyghosty0 e4f70144e9 Unity split-binary builds expect an OBB too (GitHub #92): analysis extra.unity_split → expects_obb, ANALYSIS_VERSION 2
analysis/unity_split.py: an XR-plugin build (Oculus XR Plugin / Unity OpenXR library) without assets/bin/Data/UnitySubsystems/ in the APK (zip names only), or BuildSettings listing more scenes than the APK has levelN files (globalgamemanagers loose, or its node read from the head of data.unity3d: only the blocks up to it). Exact on the 48 Unity APKs of both dump folders: all 13 split builds flagged, none of the 17 full builds (whose OBBs are asset bundles or sound banks). The missing-OBB warning and launch-test finding now cover them; existing entries are re-analysed at the next start.
2026-10-08 16:39:12 -04:00
spoopyghosty0 020334b37b OBBs found by file name: (main|patch).<versionCode>.<package>.obb next to the APK, in an obb folder beside an apk folder, or in a SideQuest backup (GitHub #85, #91)
quest_dump.find_data: after the folder-layout checks, search the APK's folder, its parent and up to 3 levels below each (folders with their own APKs are other games) for the package's expansion files; the folder with the APK's own versionCode wins, per kind the newest file not newer than it, else any version. When that folder holds other things too (the APK, other games' OBBs), the entry gets data_files and only those files are uploaded, counted and deleted with the game; no language-pack/content-file lookup there. Both dump folders scan identically (62/47 games).
2026-10-08 16:39:11 -04:00
spoopyghosty0 24a98ab263 Linux apps use their own icon (agent v64): Desktop Mode entry, Steam shortcut, library
The agent copies an AppImage's .DirIcon / the bundled .desktop file's Icon= (hicolor, pixmaps; symlinks resolved
and kept inside the app folder) to <anchor>/artwork/app-icon.{png,svg} at finalize_linux and when menu entries are
refreshed, and uses it for the menu entry's Icon= and the Steam shortcut (PNG only) unless the user chose an icon
(artwork/.icon-source = custom, sent by the PC with every art upload). StartupWMClass comes from the app's .desktop
file. A PNG goes back to the PC and becomes the library icon when there is no pick or store icon (no .picked;
.app-icon marker); folder apps get it at add time.

Closes #99
2026-10-08 16:33:16 -04:00
spoopyghosty0 58563b99a5 Re-analyse library entries an older FramePort analysed (GitHub #104)
detect.ANALYSIS_VERSION (stored as analysis.extra.analysis_version, bumped
whenever analyze() gains a field): Quest/Android entries below it whose APK
still exists are analysed again in a background thread at the GUI's start
and before a build (pipeline.refresh_analyses). Only analysis and suggested
change; recipes the user didn't edit follow the new suggestion (e.g. an SDL
app gets frame.sdl_clipboard once sdl_java exists), user recipes, tags, art,
titles and builds stay. An unreadable APK keeps its entry and is marked
analysis_failed (not retried until the next bump); a missing one is tried at
a later start. Analyze again sets the version too. Rift/Linux entries skipped.
PLAYBOOK row + CLAUDE.md note.
2026-10-08 16:25:35 -04:00
spoopyghosty0 9013a7d13c Catalog: AgeOfJoy (works)
Closes #103
2026-10-08 16:14:38 -04:00
spoopyghosty0 f36a17b46a Catalog: Pistol Whip (works)
Closes #100
2026-10-08 16:14:36 -04:00
spoopyghosty0 7335ff2ce5 Catalog: VR HOT Quest (works)
Closes #98
2026-10-08 16:14:33 -04:00
spoopyghosty0 21c039f9b3 Catalog: Retronika (works)
Closes #97
2026-10-08 16:14:31 -04:00
Lucas-Mathieu 8814b1ce56 Merge remote-tracking branch 'origin/main' into fix/batman-cutscene-playback
# Conflicts:
#	src/frameport/pipeline.py
2026-10-08 17:49:12 +02:00
spoopyghosty0 3e8a480ea6 Android version / web wrapper: warnings only, never unsupported from the manifest alone (owner's call): the recipe notes, game page (warning callout) and CLI say what the manifest asks for; a launch test's triage (android-too-new, web-wrapper) decides 2026-10-07 23:08:36 -04:00
spoopyghosty0 ea2cd893b4 Linux apps in Desktop Mode's menu: per-app switch on the game page, docs
The game page's "What FramePort will do" for a Linux app gets a Desktop Mode switch ("In the menu and on the
desktop", default on): kept in the library entry (desktop_entry; patches don't apply to Linux apps), passed to
finalize_linux at install and applied at once on the Frame through the agent's desktop_entry command when the app is
installed. The agent side (menu + desktop .desktop files, launcher with FRAMEPORT_DESKTOP=1, refresh for existing
installs, removal on uninstall/purge) came with agent v63. Help text desktop_entry, INSTALL/FRAME_RUNTIME/PLAYBOOK,
CLAUDE.md. Game Mode's Steam Input problem from the report is separate.

Closes #84
2026-10-07 22:46:38 -04:00
spoopyghosty0 a90a8c27dc Install to and move games to a microSD card: Frame page Storage section, game menu Move to…
The Steam Frame page lists the Frame's drives (filesystem, free space, games on each; exFAT/NTFS cards say why they
can't hold games) and sets where new games go (library setting install.drive, default internal storage). Game menu
→ "Move to…" (Frame-installed games, agent v63) picks a drive in a dialog and queues a Frame job that follows the
agent's copy with progress (cancellable until the copy starts). The game page and the Frame page's installed list
show "on SD Card" / "SD Card not inserted"; a game whose card is out counts as installed, not "Not installed".
Help texts install_drive / move_game, ui_smoke --fake-frame drives + the Move dialog, docs (FRAME_RUNTIME "Where
FramePort keeps games", INSTALL, PLAYBOOK row, CLAUDE.md).

Closes #90
2026-10-07 22:46:37 -04:00
spoopyghosty0 9d0d72c40a Agent v63: games on another drive (microSD) and Desktop Mode entries for Linux apps
#90: `drives` lists internal storage, the drives under /run/media (from /proc/mounts) and the drives of Steam
library folders, with free space and whether they can hold games (vfat/exfat/ntfs can't: Lepton data and Proton
prefixes need Unix permissions and symlinks; read-only mounts neither). Games on a drive live in
<mount>/FramePort/<pkg>; the anchor stays internal, so the Steam shortcut never changes. prepare/prepare_pcvr/
prepare_linux take dest (free space from it); a drive that isn't mounted is an error, never a silent fallback to
internal storage, and an installed game keeps its folder. `move` (refused while the game runs, free-space check)
renames on the same drive, else copies with cp -a (in podman's user namespace when podman is there: container-owned
files), checks file count + bytes, retargets symlinks into the old folder (LibOVRRT redirect), points launch.sh at
the new folder (Quest: the app_dir line; Linux/PC VR: written again from the install record, which now keeps env and
game args) and rewrites deployment.json before removing the old copy; detached via systemd-run with a status file
(move_status). list_installed adds drive + drive_missing; launch refuses a game whose card is out; cleanup may remove
leftovers in a drive's FramePort folder (never an installed game); purge/uninstall remove an empty FramePort folder.
PC: install/drives.py (list, setting install.drive, move with progress, picks a running move up again), targets
pass dest for Quest/PC VR/Linux installs, CLI `frameport frame drives`, `frameport frame move <pkg> --to`,
`frameport install --dest`.

#84: finalize_linux writes ~/.local/share/applications/frameport-<slug>.desktop (+ an executable copy on ~/Desktop
when it exists; Exec quoted per the Desktop Entry spec, X-FramePort-Package marks ours) unless desktop_entry is off;
`desktop_entry` command switches it per app; ensure_host_fixes adds entries for existing Linux installs and drops
stale ones; uninstall/purge remove them. The Linux launcher with FRAMEPORT_DESKTOP=1 skips the Steam-parent
watchdog and Steam's display (upgrade_launchers updates existing launchers).
2026-10-07 22:46:36 -04:00
spoopyghosty0 56d2ac117f Missing OBB: analysis extra.expects_obb (Unreal's GameActivity.bHasOBBFiles, UE4 and UE5 names); a game that expects one but has no data folder gets an error callout on the game page, a question before install (default: skip) and a warning in frameport scan/install, and a launch test without frames gets the missing-obb finding from the library (GitHub #85: TRIANGLE STRATEGY was installed without its OBB and hung silently after OVRPlugin's JNI_OnLoad). In the dumps every Unreal game with the flag has its data folder 2026-10-07 22:42:41 -04:00
spoopyghosty0 cb8202d891 Scan: OBBs in more backup layouts (quest_dump.find_data_dir): a <package> folder with .obb files up to 3 levels below the APK's folder (obb/<package>/, OBB/, Android/obb/<package>/) or 2 below its parent, skipping neighbouring folders with APKs of their own (other games/versions); <game>/apk(s)/ + <game>/obb/<package>/ (SideQuest-style backups) is one game named after <game>. The data folder is always the one holding the .obb files (obb/<package>/ used to be sent as obb/ and land one level too deep). Both dump folders scan exactly as before 2026-10-07 22:42:40 -04:00
spoopyghosty0 029b0674d1 Web wrappers: a Trusted Web Activity (manifest meta-data android.support.customtabs.trusted.DEFAULT_URL, resolved through resources.arsc, or androidbrowserhelper's LauncherActivity) is analysis extra.web_wrapper with its URL; suggested status unsupported, the game page/CLI say to open the site in a browser (GitHub #86 Mahjong Table VR opened Meta's com.oculus.browser, which the Frame doesn't have). Triage web-wrapper 2026-10-07 22:42:39 -04:00
spoopyghosty0 c852473a43 Android version gate: analysis records the APK's minSdk (extra.min_sdk, read from the original: OVRPort lowers it to 29); above 32 the suggested status is unsupported and the game page/CLI say which Android it needs (GitHub #71/#72: minSdk 34 apps crash at start on android.window / VarHandle fences, Lepton runs Android 11). minSdk 32 stays allowed: 16 working catalog games declare it. Triage android-too-new 2026-10-07 22:42:38 -04:00
spoopyghosty0 acf1ef1da2 haptic_fix: keep revision 2 (owner's call, drop this commit to keep #81's bump)
The PCM conversion is preventive (Sniper Elite VR and Hyper Clinic send envelopes), and revision 3 would show
'Update on Frame' for every build with adapter.haptic_fix (suggested for every OVRPlugin game), including builds
where upstream.py already left the workaround out. Same reasoning as rect_clamp. New builds get the PCM conversion
anyway (the artifact is rebuilt).
2026-10-07 22:27:16 -04:00
spoopyghosty0 5fe120e897 Sniper Elite VR follow-up: merge the new haptic OOM PLAYBOOK row into the existing one (same OVRPort bug, now with the upstream-fix note); wrap unity_oculus_check's description to 120 columns (ruff); regenerate docs/GAMES.md 2026-10-07 22:25:43 -04:00
spoopyghosty0 41624c8dbd Rebuild libfp_ovrp.so and libframe_xrshim.so from the reviewed sources (native/build.py --only ovrpshim,xrshim, NDK r27c; the previous sources reproduce the committed artifacts byte for byte) 2026-10-07 22:23:19 -04:00
UnicronNL e8ec39db86 Sniper Elite VR: works (GitHub #81)
- native/ovrpshim: libunity.so's ovrp_BeginFrame/ovrp_EndFrame go through the shim; the frame wait waits <= 50 ms
  for the last waited frame to begin and skips otherwise (the game deadlocked at its Init scene when Unity skipped a
  begin); a begin/end of another index while a wait is outstanding gets the waited index. The physics-step
  ovrp_Update2 is held back (prediction 0 located the controllers in the past on the Frame: the hands lagged).
  frame.unity_oculus_check revision 5.
- native/xrshim: PCM vibrations (XrHapticPcmVibrationFB) become one plain vibration too; haptic_fix revision 3.
- Catalog: works with frame.unity_oculus_check + haptic_fix, min_app 0.12.1. Triage unity-frame-not-begun (info),
  PLAYBOOK rows and how to get all-thread backtraces with gdbserver64 inside the container, test.
2026-10-07 22:21:08 -04:00
spoopyghosty0 936d4b188b BONELAB: catalog note leads with the per-build status (GAMES.md showed only 'One recipe for both builds.'); regenerate docs/GAMES.md (also adds the missing Doom3Quest row) 2026-10-07 22:20:24 -04:00
UnicronNL e9ab1489cc BONELAB 1.2974: frame.slz_vulkan_hooks (GitHub #82)
Stress Level Zero's graphics plugin (libSLZQuestNative.so) hooks Unity's Vulkan start-up and vkCreateSampler; on
the Frame its vkCreateInstance wrapper calls an invalid pointer right after OVRPlugin's pre-init instance is
destroyed (pc 0, a jump into an unloaded library, or a hang). The new patch turns the plugin's two registrations into
no-ops (found through its exported functions, 4 bytes each), so Unity starts Vulkan itself; ~35 s of shader
prewarming without the plugin's pipeline cache, then 72 fps (headless). One BONELAB recipe serves 1.2068 and 1.2974.
Triage slz-vulkan-hook-crash, PLAYBOOK row, tests with a fixture built from tests/fixtures/src/fakeslz.S.
2026-10-07 22:15:57 -04:00
spoopyghosty0 1043eb1d1b Catalog: Richie's Plank Experience (works)
Closes #95
2026-10-07 22:13:33 -04:00
spoopyghosty0 0f444da595 Catalog: RUINSMAGUS (works)
Closes #89
2026-10-07 22:13:27 -04:00
spoopyghosty0 fda644d036 Catalog: GORN2 (works)
Closes #88
2026-10-07 22:13:19 -04:00
spoopyghosty0 fa0fbbd29a Catalog: Time Crisis VR (Experimental) (works)
Closes #80
2026-10-07 22:13:14 -04:00
spoopyghosty0 3446999109 Upstream fixes replace our workarounds per build (patches/upstream.py)
Each build probes OVRPort's output for registered upstream fixes and leaves out the workarounds they make
unnecessary (recipes unchanged: builds with an older runtime keep them). Logged ("not needed: ..."), recorded in
build.superseded, left out of settings.conf at install, shown on the game page and in `frameport show`;
FRAMEPORT_KEEP_WORKAROUNDS=1 turns it off. Registered: ovrport.haptic_envelope (-> adapter.haptic_fix) and
ovrport.microphone_stream (-> frame.ovr_microphone), both fixed in OVRPort runtime 3.4.3-aa54c3f (ovrport/app#73;
haptics verified in the headset with Lucky's Tale). Probes checked against both real runtimes; fixtures in
tests/fixtures/src/fakeruntime.S.
2026-10-07 21:02:12 -04:00
Lucas-Mathieu e9eedb2241 Merge remote-tracking branch 'origin/main' into fix/batman-cutscene-playback
# Conflicts:
#	artifacts/SHA256SUMS
2026-10-08 01:57:46 +02:00
Lucas-Mathieu d3a35c307a Fix Batman native cutscene decoding and stereo composition 2026-10-08 01:57:29 +02:00
spoopyghosty0 d6f87f79a6 Live view: status updates from the ticker/start/stream-end threads go through components.LoopUpdater (the GUI logged 'dropped a patch for unknown control' during the owner's test, the same cause the Monitor tab fixed) 2026-10-07 19:52:09 -04:00
spoopyghosty0 24a1ef9f1d Live view: less delay with sound. The -1 s video input offset (1080p fix) made ffmpeg release video in clumps (output gaps up to 550 ms: a longer, stuttering browser delay, worse with sound); -0.25 s keeps 1080p from stalling and the output steady (measured on the Frame with sound playing). Player: no speed-up while sound is on (Chrome keeps ~0.6 s of audio ahead and stalled 8x/30 s at 1.1x, 1-2x without; same ~1 s lag; muted ~0.3 s); the Sound on tooltip says so 2026-10-07 19:44:46 -04:00
spoopyghosty0 ae4904c7d9 Live view: 1080p no longer drops frames with sound on (ffmpeg paced its inputs against pulse's late audio and stopped reading the video for up to 0.7 s, blocking fp_venc's writes; -itsoffset -1 on the video input keeps it from counting as ahead). Found with fp_venc's new timing stats (write_ms 17-38 avg, 260 max at 1080p) and a busy 1080p replay into the real pipeline: 20 s took 34-47 s with sound, exactly 20 s with the fix; output A/V spans unchanged 2026-10-07 19:13:45 -04:00
spoopyghosty0 b142f7c0ac Live view: Stop ends a backed-up stream (fp_venc blocked in a write never saw stdin EOF and ffmpeg's output wasn't drained after the channel closed: both stayed on the Frame holding the headset view open, found after the owner's 1080p run). The script reports its process group; close() waits 2 s and then kills the group. Helper uploads use their own temp name (two starts raced on fp_venc.new). Verified on the Frame: forced kill path and the normal stop both leave nothing running 2026-10-07 18:37:11 -04:00
spoopyghosty0 934f356927 Live view: the panel warns when the Frame drops frames (encoder stats per 10 s: late + skipped slots >= 5 %, 'choose a lower quality'); fp_venc stats add per-window convert/write timing and no-free-buffer counts to find why 1080p stalled (owner: 1080p choppy, 360p smooth; log: 208 of 320 slots, 172 late, 104 skipped) 2026-10-07 18:09:15 -04:00
spoopyghosty0 a61764960d Live view: even frame timestamps and VBR after the first headset test
Owner's headset test (720p): heavy compression artifacts and many dropped-looking frames.
- Frames stamped on arrival (wall clock) bunched when ffmpeg read several at once (gaps of 0-10 ms and 45+ ms). The
  input stays on the wall clock (read in step with pulse's audio; setts alone held output ~7 s), and setts now
  numbers the output frames on fp_venc's fps grid: every gap exactly 1/fps on the Frame, audio aligned.
- fp_venc --peak: VBR capped at the peak (else CBR as before), level picked for the peak. The hardware path uses
  1.5x peaks and higher targets (360p 1.5, 480p 2.5, 720p 5, 1080p 8, Full 10 Mbit/s); 3 Mbit/s CBR blurred every
  head turn. The x264 fallback keeps its rates.
- fp_venc's info/stats lines go to the app log (late/skipped frames next time); its errors still explain a stop.

Verified on the Frame: probe with VBR (no refused control); end to end through livestream.start at 720p32: 403
frames all 31 ms apart, audio 0-12.57 s next to video 0-12.58 s, late viewer on its keyframe at once, nothing left
after stop. Picture quality with motion still needs the headset.
2026-10-07 18:00:59 -04:00
spoopyghosty0 55a376cdfd fp_venc: exact NEON fast paths for 3:2 (720p) and 3:1 (360p) scaling
The box boxes repeat every 3 source pixels at these ratios, so the averages become rounding shifts (3:2: block
sizes 1, 2, 4) or an exact multiply (3:1: x7282 >> 16 = /9 for every sum), with no per-pixel scalar loop. Same
bytes as the generic path; 480p (852 px wide, irregular) keeps the generic path. Self-test adds 1158x648 -> 432/216
(columns left over after the 48-pixel steps) and times all four qualities.

Frame (2026-10-07): selftest ok (184 cases); 1920x1080 -> 720: 1.3-1.65 ms (was 5.6), -> 360: 0.7 ms,
-> 1080: 0.6-1.0 ms, -> 480: 2.8 ms.
2026-10-07 17:50:59 -04:00
spoopyghosty0 da7655ee25 Live view hardware encoder: fixes from the first device run
- fp_venc: accept the source's buffer count (the Frame's v4l2loopback has max_buffers=2; asking for 3 failed the
  probe); OUTPUT buffers remember which picture they hold, so repeats (standby, still scenes) skip the conversion
  (720p: 35% -> 2.5% of a core with the headset asleep).
- Pipeline: raw H.264 stamped on arrival (-use_wallclock_as_timestamps, same clock as pulse) with a 32-byte probe:
  -framerate was ignored, -fflags nobuffer lost the first seconds, frames numbered from 0 held all output ~7 s next
  to the sound. frag_keyframe so a requested keyframe starts a fragment (a joining viewer starts there).

Verified on the Frame (headset asleep): selftest ok (104 cases), probe at 360p-1080p, end to end through
livestream.start: 720p36 + AAC in 0.1 s fragments, audio and video spans match, a second viewer starts on its
requested keyframe at once, nothing left running after stop; FP_VENC_DISABLE=1 falls back to x264.
2026-10-07 17:50:57 -04:00
spoopyghosty0 0ae754fa5d Live view: hardware H.264 encoder (fp_venc), x264 stays as fallback
native/venc/fp_venc: own clean-room driver of the Frame's iris encoder (V4L2 stateful encoder interface, written from
native/venc/SPEC.md = kernel docs + values measured on the Frame). Reads SteamVR's headset-view webcam, box-scales and
converts RGB24 to NV12 (NEON, bit-identical scalar reference), CBR H.264 with SPS/PPS on every IDR, one frame per slot
of an even fraction of the panel rate read through DRM (96 Hz -> 32 fps). stdin "k" = keyframe, EOF = stop;
--probe/--selftest. Static freestanding aarch64 binary in artifacts/linux-arm64-bin (reproducible).

livestream: the script probes fp_venc and pipes it into ffmpeg (-c:v copy + AAC), else the old x264 30 fps path; the
helper is synced to ~/.local/share/frameport/bin by sha256 at stream start (no agent change); a new viewer asks for a
keyframe and waits for it; the status line shows the encoder and fps. Tests: hardware/fallback script branches,
keyframe-on-join, helper sync; tests/test_venc.py compares convert.c with a Python reference (native marker).
Not yet run on the device.
2026-10-07 17:50:55 -04:00
spoopyghosty0 ecfd2408cf Monitor: the detail boxes' first update goes through the event loop like the ticks (sent from the connect thread it could arrive after a tick's patch: 'dropped a patch for unknown control'); README screenshot with the new layout 2026-10-07 17:33:21 -04:00
spoopyghosty0 44dfd43692 Monitor feedback: updates from the stream's thread go through Flet's event loop (components.LoopUpdater: the window showed nothing until a click and the charts moved in bursts); intervals 0.1/0.25/0.5 s (0.5 s default; processes still scanned every 2 s, their GPU % averaged over it); charts in 1-second buckets (2 minutes at any interval); same-name processes with one parent collapse into a group row (click to open, end or force-kill all); tile headers line up; detail cards share one height; temperature boxes with mini charts and a Fan box; 'Monitor is using … of the Frame's CPU' 2026-10-07 17:26:20 -04:00
spoopyghosty0 29876ec046 README: Monitor section + screenshot (docs/images/monitor.png, ui_smoke --fake-frame --game: the fake monitor follows --game and sends two minutes at once so the charts are full). Monitor game card: the game's artwork is an art_fill control inside the box (copying its image onto the box showed nothing) 2026-10-07 17:05:15 -04:00
spoopyghosty0 3667f504ec Monitor agent after device tests (4XVR on the dev Frame): full names for processes whose comm the kernel truncated (Android's last 15 characters), power rails per cluster every 5 s and battery current/voltage every 2 s (I2C reads), temperatures every 2 s, fast render-fd rescans only for busy young game processes, end_game reports a game that wasn't running 2026-10-07 16:55:11 -04:00
spoopyghosty0 375b976dcd Monitor tab: a live view of the Frame while the tab is shown (running game with fps, CPU/GPU/memory/temperature/power/battery tiles with 2-minute sparklines, details: per-core load, sensors, power split, network) and its processes (filter Game / Steam & SteamVR / All, search, sort; right-click: end, force kill, end game; critical programs ask again). frame/monitor.py = session + pure helpers, C.Sparkline/MeterBar on Flet's canvas (no charts extension), ui_smoke FakeMonitorSession + --only, docs 2026-10-07 16:55:09 -04:00
spoopyghosty0 2a74e5ff64 Agent v62: _monitor stream for the Monitor tab (CPU/GPU/memory/pressure/temperatures/fan/power rails/battery/network, running FramePort games with fps from FrameBridge pacing and container cgroup usage, processes grouped by game/Steam/SteamVR/desktop with per-process GPU % from DRM fdinfo; end a process or a game). Kernel threads, command lines and render fds are cached so a sample stays cheap on the Frame 2026-10-07 16:55:06 -04:00
spoopyghosty0 0c623c2efc Install question: each file's name on its own line (long names end in an ellipsis, full name on hover), its type, size and checksum below; the narrow label column wrapped long file names 2026-10-07 16:51:32 -04:00
spoopyghosty0 d49b3ae884 Install links: FramePort-only manifest fields (frameport.description / frameport.icon) shown in the install question and used as the game's icon and description; readable titles for bare file links; handler scripts wait for the open window to take a link (a just-closed window's heartbeat swallowed clicks on Windows), the heartbeat is removed on close, and the Windows handler runs under conhost --headless (no console flash) 2026-10-07 16:35:21 -04:00
spoopyghosty0 f811261507 Lint: line lengths, import order, unused loop variable (ruff) 2026-10-07 16:09:03 -04:00
spoopyghosty0 ec701e6e56 Install links (FrameDrop's "Install with FrameDrop" button protocol), drop files on the Library, add a lone Windows .exe, VR / flat window choice, x86_64 Linux apps through FEX
- deeplink.py: framedrop:// and frameport:// links and the pasted https://framedropvr.com/install?manifest=|url= link; manifest framedrop.install/v1; https only (http on loopback), no credentials, no LAN addresses (also after DNS and redirects), sha256 checked, cancel/mismatch leave no .part
- urlhandler.py: per-scheme registration (Settings → Install links, links.framedrop / links.frameport, default on; another program's scheme only taken on request) through a handler script that queues the link and starts FramePort (a flet build bundle can't take a URL argument); the GUI's heartbeat + link inbox
- GUI: Add games → Install from a link… and Add a Windows program (.exe)…; confirmation before any download; files dropped on the Library (packaged app); CLI frameport open-link
- patch device.display_mode (Automatic / VR / Flat window), verified on the Frame with 4XVR
- x86_64 Linux apps run through FEX (agent v61: FEX installed unattended, STEAM_COMPAT_DATA_PATH set, RootFS from SteamOS's /usr/share/guestos/fex-mesa); verified on the Frame with an x86_64 test program; triage linux-x86-no-fex
2026-10-07 16:06:40 -04:00
spoopyghosty0 360dc105e1 Type on Frame is a sidebar tab (was a dialog): the virtual keyboard is connected while the tab is shown and removed when another tab opens or the Frame disconnects; the Frame page button and the game menu open the tab, the keyboard icon on the Frame card is gone. README screenshot redone 2026-10-07 09:24:17 -04:00
spoopyghosty0 892c7c13bd FrameBridge input_diag: report failed vibrations from the adapter's own xrApplyHapticFeedback (always hooked for haptic_scale, so the PR's wrapper never ran); adapter artifacts rebuilt 2026-10-06 23:13:52 -04:00
Molier 3b6128a1b0 FrameBridge input_diag (off by default, hooked only when on): logs each controller profile a game suggests with the runtime's answer (every path of a rejected one), the profile the runtime reports for each hand, OpenXR functions the runtime lacks and failing input, haptics and perf calls, each line once. Triage signature input-call-failed, PLAYBOOK row, host test tests/test_input_diag.py; artifacts not rebuilt 2026-10-06 23:13:51 -04:00
spoopyghosty0 4c42a528bd Merge pull request #79 from spoopyghosty0/catalog/issue-77
catalog: com.drbeef.doom3quest
2026-10-06 23:08:48 -04:00
github-actions[bot] 0e7c5264a0 catalog: com.drbeef.doom3quest (from #77) 2026-10-07 02:59:42 +00:00
spoopyghosty0 69a4fa6fa7 Notes: upstream trackers (#73 microphone, #74 haptics, #75 VrApi bridge) linked from the workarounds and the release checklist 2026-10-06 20:37:25 -04:00
spoopyghosty0 e6b9808beb Catalog: BlazeRush (unsupported: menu room unusable) 2026-10-06 18:22:47 -04:00
spoopyghosty0 b34330dc85 Catalog: Lambda1VR (works; needs its game data) 2026-10-06 18:22:45 -04:00
spoopyghosty0 ae69fe3831 Catalog: The Boys VR (works with space warp off) 2026-10-06 18:22:42 -04:00
spoopyghosty0 6d2dc95cc8 Catalog: Jurassic World Aftermath Collection (works; frame.vrapi_stub) 2026-10-06 18:22:40 -04:00
spoopyghosty0 474be9d34b FramePort 0.12.0 2026-10-06 18:21:32 -04:00
spoopyghosty0 7b4dff7d84 Notes: 2026-10-06 issue triage round (headset results, what was ruled out) 2026-10-06 18:19:12 -04:00
spoopyghosty0 885070a00c Catalog: Metro Awakening plays with space warp off and without Valve's VALVE_rpo layer (random jumping polygons otherwise; owner's headset test) 2026-10-06 17:22:56 -04:00
spoopyghosty0 67b58238a0 Catalog: Pinball FX VR with space warp off (stutters gone after loading in the owner's headset test) 2026-10-06 17:08:10 -04:00
spoopyghosty0 a1c87618f6 VrApi bridge: upstream-patches/input.cpp.patch (FramePort's input diagnostics) 2026-10-06 17:07:40 -04:00
spoopyghosty0 b4cec19283 VrApi bridge: input diagnostics also log the controller types asked for (and refused), button bits seen and thumbstick deflection (BlazeRush: no thumbstick, no hands) 2026-10-06 17:07:30 -04:00
spoopyghosty0 109c7e449c FrameBridge: a vibration with amplitude 0 becomes xrStopHapticFeedback (OVRPlugin stops vibrations that way; the last buzz otherwise ran its full 2 s in Jurassic World, The Boys VR, Creed) 2026-10-06 16:28:45 -04:00
spoopyghosty0 05ad7e4d25 GL shim: with GL_EXT_multisampled_render_to_texture hidden, its two functions become single-sampled stand-ins (TBXR calls them regardless: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, black eyes in Lambda1VR); frame.tbxr_vendor links the shim into TBXR's library 2026-10-06 15:37:08 -04:00
spoopyghosty0 1e96abebbb Agent v59: close Steam's 'Resume game' menu for 120 s after the first VR frame, up to 10 times (it came back after the first 30 s); still stops once the player opens the dashboard 2026-10-06 15:24:16 -04:00
spoopyghosty0 69da709ea2 Vibration: haptic_fix converts envelopes with their RMS instead of their peak (vibrations felt far stronger than on a Quest); new per-game setting haptic_scale ('Vibration strength') scales every vibration in FrameBridge and logs the first requests. VrApi bridge: input/vibration diagnostics every 5 s (BlazeRush controllers) 2026-10-06 15:22:57 -04:00
spoopyghosty0 d5f9c248e0 frame.avatar_stub: replace Meta's avatar loader with a do-nothing library when it can't find its driver and aborts the game (BlazeRush: OVRAvatar-Loader DisplayErrorAndExit); suggested by triage avatar-driver-missing 2026-10-06 14:53:53 -04:00
spoopyghosty0 cc39547e33 FrameBridge: add XR_KHR_opengl_es_enable when an app enables no graphics API extension (Lambda1VR's TBXR creates a GLES session without it; Meta's runtime tolerates that); log the final instance extension list once per launch. Lambda1VR now runs headless at 72 fps 2026-10-06 14:50:34 -04:00
spoopyghosty0 096d24e42b FrameBridge: when xrCreateSession fails with XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, ask for the graphics requirements on the app's behalf and retry once (Lambda1VR: Failed to create XR session: -50); triage graphics-requirements-missing 2026-10-06 14:33:02 -04:00
spoopyghosty0 2995413434 VrApi bridge: vrapi_PollEvent returns ovrSuccess_EventUnavailable (1002), vrapi_SetTrackingSpace returns an ovrResult, vrapi_CreateTextureSwapChain/2 take VrApi's 32-bit format enum (found while preparing the upstream PRs) 2026-10-06 14:31:40 -04:00
spoopyghosty0 4b34dbd218 Platform stubs: also stub ovr<Enum>_ToString helpers OVRPort's loader lacks (BlazeRush: ovrPeerConnectionState_ToString); ToString stubs return an empty string, not NULL; triage missing-ovr-symbol matches them 2026-10-06 14:08:20 -04:00
spoopyghosty0 a775e63e6d Install: build a game that was never built instead of failing with KeyError 'apk' (frameport install right after a scan) 2026-10-06 14:01:08 -04:00
spoopyghosty0 3cd4affcf6 frame.ovr_microphone: don't suggest it from libil2cpp.so (Unity's C# platform wrapper names every Meta function, so every Unity game with the Platform SDK matched); triage ovr-microphone-crash still finds a Unity game that crashes there 2026-10-06 13:58:56 -04:00
spoopyghosty0 51e553039a Catalog: Beat Saber (com.beatgames.beatsaber.lj369vr) (works)
Closes #68
2026-10-06 13:53:36 -04:00
spoopyghosty0 27ff49a137 Catalog: Creed (works)
Closes #60
2026-10-06 13:53:33 -04:00
spoopyghosty0 e70acf9269 Catalog: BodyCombat (works)
Closes #56
2026-10-06 13:53:29 -04:00
spoopyghosty0 1f6fce0fcc Catalog: Pinball FX VR (works with issues, MR not yet)
Closes #50
2026-10-06 13:53:25 -04:00
spoopyghosty0 188cb8fe68 Metro Awakening: libfp_vk.so rebuilt with the shim's new fixes; catalog entry with the contributor's recipe (use_alt, vk_spec_fixes, vk_hide_fdm); docs/GAMES.md regenerated; lint 2026-10-06 13:46:53 -04:00
UnicronNL 0744a126cb Vulkan shim: drop depth resolves of subpasses without depth, leave out null-image barriers and refuse null-image views (vk_spec_fixes), vk_hide_fdm hides fragment density maps (Metro Awakening crashed in the Frame's Vulkan driver, GitHub #65) 2026-10-06 13:46:52 -04:00
spoopyghosty0 1c8a0d63e7 BONELAB: libfp_ovrp.so rebuilt with the user-presence wrapper; catalog status 'issues' (1.2068 plays, the newer 1.2974 still crashes at start); docs/GAMES.md regenerated 2026-10-06 13:46:51 -04:00
UnicronNL 124ec594a6 frame.unity_user_presence: report the headset as worn to Unity's Oculus XR Plugin (BONELAB 1.2068's rig froze: OVRPlugin's ovrp_GetUserPresent2 turns 0 while worn, GitHub #66) 2026-10-06 13:46:31 -04:00
spoopyghosty0 90b528f9f2 Lint: wrap a long comment 2026-10-06 13:46:30 -04:00
UnicronNL 2da6082166 frame.ovr_microphone: guard OVRPort's ovr_Microphone_GetOutputBufferMaxSize against a not-yet-opened stream (The Walking Dead: Saints & Sinners Ch. 2 crashed after the logo, GitHub #67) 2026-10-06 13:46:30 -04:00
spoopyghosty0 3e61b07254 frame.asset_files: list the game data's *.pak content files as installed default asset files and answer DownloadById at once with the path (Star Wars: Tales from the Galaxy's Edge went black after loading, GitHub #61); shares the language-pack library 2026-10-06 13:46:08 -04:00
spoopyghosty0 48c3716ef5 frame.tbxr_vendor: Team Beef ports load openxr_loader_<maker> and pick Meta's path only for "meta": add an empty libopenxr_loader_valve.so and let "valve" match those checks (Lambda1VR stopped at start, GitHub #59) 2026-10-06 13:28:10 -04:00
spoopyghosty0 dca2d8b762 VrApi bridge: vrapi_PollEvent, RecenterPose, SetDisplayRefreshRate, GetSystemPropertyFloatArray (BlazeRush couldn't load: cannot locate symbol vrapi_PollEvent, GitHub #57); static check 'VrApi functions resolvable', triage vrapi-symbol-missing; upstream-patches regenerated (graphics.cpp.patch was stale: the Vulkan format twin was missing from it) 2026-10-06 13:23:52 -04:00
spoopyghosty0 2c4bbdbfec frame.vrapi_stub: replace Meta's leftover VrApi loader with a same-exports library that answers 0 (OVRPlugin on OpenXR called vrapi_SetPropertyInt before init and the loader aborted, GitHub #62); triage vrapi-before-init, direct-vrapi no longer matches it 2026-10-06 13:12:59 -04:00
spoopyghosty0 8a08733be8 Agent v58: Play re-adds a devkit entry Steam forgot (no NOT_IN_LIBRARY, no Steam restart); installs and art updates of devkit games only copy art; the app treats Steam's AppError_16 as already starting and ignores repeated Play clicks for 20 s (GitHub #41/#42) 2026-10-06 13:09:39 -04:00
spoopyghosty0 d7193bea19 device.foveation: per-game choice for Valve's eye-tracked foveation layer (default / fixed = FDM_DEBUG=disable_offsets / off = VK_INSTANCE_LAYERS=""), catalog field foveation (GitHub #69) 2026-10-06 13:06:36 -04:00
spoopyghosty0 c3522a05bb macOS: keep the entitlements when ad-hoc signing (re-signing stripped them; Scan a folder failed with ENTITLEMENT_NOT_FOUND, GitHub #63) 2026-10-06 13:06:35 -04:00
spoopyghosty0 8a9a428f1e Delete files on this PC: also remove the download manifest next to the game when it lists only the game's files (the folder stayed, so the download manager still listed the game) 2026-10-06 13:06:34 -04:00
spoopyghosty0 919d059add Notes: the jni build override and re-tagging a failed release build 2026-10-06 12:14:37 -04:00
spoopyghosty0 674c26f2d9 Build: override jni to 1.1.0 instead (jni_flutter 1.0.4 also generates bindings that require jni ^1.1.0; Flet's template pins 1.0.0) 2026-10-06 12:04:20 -04:00
spoopyghosty0 a6daa5cccb Build: pin jni_flutter 1.0.4 (1.0.4+1, published today, requires jni ^1.1.0 but Flet pins jni 1.0.0; all flet build bundles failed) 2026-10-06 11:54:47 -04:00
spoopyghosty0 6f89123017 FramePort 0.11.1 2026-10-06 11:44:01 -04:00
spoopyghosty0 518c94d79f Vader Immortal: Episode I catalog entry (works with issues, GitHub #49): plays the intro, then stays on its loading card; plain recipe without diagnostics 2026-10-06 11:42:04 -04:00
spoopyghosty0 edf9f494e8 Agent v57: one launcher per game (flock on <base>/.launch.lock). Play pressed again while Lepton still booted made the second Lepton stop the first container and both died (Vader Immortal, BattleSisters); a second launch now exits and leaves the first running. upgrade_launchers adds it to existing launchers; verified on the device 2026-10-06 11:25:56 -04:00
spoopyghosty0 0db053c31f FrameBridge snapshot=N: every N seconds the left-eye image a GLES game submits is saved as fb_snap_0-7.ppm in its files folder (headless launches have a black headset view). Vader Immortal: the intro plays, then its loading card never advances 2026-10-06 09:26:38 -04:00
spoopyghosty0 7439f082db BattleSisters works (owner-verified 2026-10-06: buttons via the Oculus device-model fix; its first controller vibration ran OVRPort's haptic-envelope bug into an 11 GB OOM kill). haptic_fix is now suggested for every game that ships Meta's OVRPlugin; existing FramePort recipes pick it up after the next update 2026-10-06 09:01:40 -04:00
spoopyghosty0 f12f4aec4c FrameBridge layer_debug: count xrAcquire/Wait/ReleaseSwapchainImage per 5 s (Vader Immortal's per-frame leak in SteamVR's runtime; hooked only with layer_debug, after the other wait/release hooks) 2026-10-06 01:23:58 -04:00
spoopyghosty0 8d95592f53 Unity 2019 built-in Oculus input on Lepton (BattleSisters, GitHub #48): libunity only reports controllers when the device model starts with "Oculus"; Lepton's Android is "Valve Lepton", so Unity polled only Go-style controllers and the game's buttons never arrived. unity_oculus_check revision 4 gives those strncmp calls length 0 (in place); on the device libunity now polls the Touch controllers 2026-10-06 01:19:47 -04:00
spoopyghosty0 44d23f778d FrameBridge diagnostics from Vader Immortal (GitHub #49): layer_debug logs xrDestroySwapchain and per-5 s xrBeginFrame/xrEndFrame counts; strip_color_bias (drop XR_KHR_composition_layer_color_scale_bias, 2 = the layer's whole extension chain) and frame_balance (end an open frame before the next begin), both opt-in. Vader leaks ~430 GPU mappings a second inside SteamVR's runtime (GPU timing command buffers per frame); none of these stop it 2026-10-06 01:07:11 -04:00
spoopyghosty0 7a40e47e67 FramePort 0.11.0 2026-10-06 00:21:37 -04:00
spoopyghosty0 9401b7fc87 Accounting+ works (owner-verified 2026-10-06: the motion warning continues with the click emulation); catalog entry needs FramePort 0.10.1 2026-10-06 00:18:20 -04:00
spoopyghosty0 e510ea88f0 ovrpshim: log ovrp_GetNodePresent for Unity's built-in XR input and report a hand node present while its Touch controller is connected (BattleSisters: Unity's XR controller devices, which its buttons are read from, never appeared) 2026-10-06 00:17:25 -04:00
spoopyghosty0 4c2b6c9dee Start-up recursion (GitHub #58): library.load() refreshes recipes from the catalog, and the catalog's first load read its auto-update setting through library.load(), which refreshed recipes again before the catalog was cached (~140 nested loads: a long blank window, or a crash in the Windows bundle). The setting is read as stored (library.peek_setting) and the catalog step can't re-enter itself 2026-10-06 00:17:14 -04:00
spoopyghosty0 cb689c576a ovrpshim: Touch trigger or A/B/X/Y presses count as Unity mouse clicks (GetMouseButtonDown icall replaced): Accounting+'s motion warning waits for a click Lepton never delivers; input probe logs trigger/grip values 2026-10-06 00:06:18 -04:00
spoopyghosty0 bd2e1a8410 unity_oculus_check revision 3: Unity's built-in Oculus input creates Touch controllers only on device model 'Oculus Quest'; Lepton's Android is 'Valve Lepton', so the compared string is repointed in place (BattleSisters: hands tracked, buttons dead although OVRPlugin reported every press) 2026-10-05 23:39:53 -04:00
spoopyghosty0 608fac9d68 unity_oculus_check: the input probe can be switched on for a diagnostic build (FRAMEPORT_INPUT_PROBE=1) 2026-10-05 23:18:14 -04:00
spoopyghosty0 919c0e291e focus_hold on by default with 5 s (the Frame's wear sensor flickers "HMD off" for 0.5-2 s while worn and Quest games pause each time; Lucky's Tale); Unity 2019 games on the built-in VR loop (no Oculus XR Plugin) get the ovrpshim frame wait (BattleSisters flooded 'outside of frame bounds' and hung the GPU); frame.ovr_trace: opt-in Meta Platform SDK request tracer (native/ovrtrace) for games stuck waiting (Vader Immortal, GitHub #49); catalog: I Am Cat pose_consistency, Lucky's Tale haptic_fix, The Room VR (all owner-verified) 2026-10-05 22:02:06 -04:00
spoopyghosty0 23f4192cfd Game page offers a newer catalog config for recipes the user edited (GitHub #10: a saved Game settings dialog stopped catalog fixes; saving without a change no longer marks the recipe as the user's); launch tests fail when frames stop while the process lives on (frames-stopped) and on Unity render-thread crashes in the GL driver (unity-render-crash) 2026-10-05 21:03:02 -04:00
spoopyghosty0 3391a981b8 Unity fixes from the 2026-10-05 headset round: unity_runtime_msaa_off also no-ops QualitySettings.set_antiAliasing; frame.unity_no_overlay_copy (The Room VR: OVROverlay's fade copy crashed Zink; works now); unity_oculus_check also for Unity 2019 without the frame-wait shim (BattleSisters starts VR; then a GPU lockup); frame.unity_gl_shim + gl_hide_msrtt (GL shim reads every settings source); xrshim converts haptic amplitude envelopes before OVRPort's dispatcher (haptic_fix; GitHub #9, found by Klownicle); FrameBridge pose_consistency (GitHub #8, proposed by Klownicle) 2026-10-05 20:55:36 -04:00
spoopyghosty0 271ce56d08 README: Live view 2026-10-05 20:05:07 -04:00
spoopyghosty0 0e47ce8f1a Live view: sound, 360p-1080p + full-size qualities, smoother catch-up
- Sound: the default output's pulse monitor (what the headset plays) as AAC in the same fMP4; the
  player starts muted (browser autoplay rules) with a Sound on button. Video timestamps go to the
  wall clock (-ts mono2abs) instead of forcing it on the pulse input, which gave bursts of AAC packets
  one shared timestamp; aresample=async=1 keeps the sound continuous.
- Late viewers start at a keyframe of the video track (audio samples are all sync).
- Qualities 360p/480p/720p/1080p scale down only; 'full' sends SteamVR's headset view at its own
  size (1920x1080 today; v4l2cam has no size option, so 2K/4K would only upscale).
- Player keeps a 0.3 s cushion and catches up at 1.1x; it seeks only when >2 s behind (seeking to the
  very edge starved playback).
2026-10-05 20:05:06 -04:00
spoopyghosty0 ad924669d3 Live view tab: stream the Frame's headset view to a browser window on the PC
Source: SteamVR's built-in v4l2cam headset view (steamvr-v4l2cam.service -> v4l2loopback 'SteamVR'),
encoded with x264 on the Frame (fps=30 before scaling, nice 10, 3 threads) as fragmented MP4 over an
SSH exec channel; ffmpeg stops when the channel closes. A relay on 127.0.0.1 keeps the init segment and
the fragments since the last keyframe for late viewers and serves an MSE player page, opened in the
default browser (Flet can't show video outside flet build bundles). Verified on the dev Frame: 30 fps
in Edge, ~0.1 s behind the newest frame, 0.34 core at 720p with a quiet picture.
2026-10-05 20:05:06 -04:00
spoopyghosty0 311277ae40 FrameBridge rect_clamp (default on): keep submitted image rects inside their swapchain; SteamVR rejected every frame of a Unity game whose eye rect ran 4 px past it (GitHub #39, PowerWash Simulator stuck at 'Waiting'); triage swapchain-rect-invalid, PLAYBOOK row 2026-10-05 19:17:36 -04:00
spoopyghosty0 bad59bfb5b Steam library fallback (agent v56, GitHub #41): Play re-registers a devkit entry Steam forgot after a restart, the console-log appid comes from the current Steam session only, and art updates also reach the devkit entry 2026-10-05 18:57:25 -04:00
spoopyghosty0 9b57c4753f Game list: Waltz of the Wizard (merged working config) 2026-10-05 18:51:06 -04:00
spoopyghosty0 1301e60be1 Play's devkit fallback finds the entry's appid in Steam's console log when Steam doesn't save shortcuts.vdf (agent v55; GitHub #42: every game showed 'Game configuration unavailable') 2026-10-05 18:50:23 -04:00
spoopyghosty0 069a74f97e Merge pull request #55 from spoopyghosty0/catalog/issue-44
catalog: com.Aldin.WotW
2026-10-05 18:48:23 -04:00
github-actions[bot] 683ae5bcf6 catalog: com.Aldin.WotW (from #44) 2026-10-05 22:47:43 +00:00
spoopyghosty0 af904c62e6 FramePort 0.10.0 2026-10-05 18:46:18 -04:00
spoopyghosty0 f2d93af973 Game list: Tetris Effect, Iron Man VR, palazzo_santacruz (merged working configs) 2026-10-05 18:44:29 -04:00
spoopyghosty0 59fb47a827 Into The Radius 2 works: catalog vk_spec_fixes (the invalid depth resolve made models flicker and windows show behind them; found with the validation layer), status works, min_app 0.9.2; notes on Vulkan validation on the Frame 2026-10-05 18:43:39 -04:00
spoopyghosty0 9e169e069b Merge pull request #52 from spoopyghosty0/catalog/issue-46
catalog: com.resolutiongames.abvriop.santacruz
2026-10-05 18:40:13 -04:00
spoopyghosty0 eed6e4aaed Merge pull request #53 from spoopyghosty0/catalog/issue-47
catalog: com.camouflaj.salmon
2026-10-05 18:40:05 -04:00
spoopyghosty0 9829ee1666 Merge pull request #54 from spoopyghosty0/catalog/issue-45
catalog: com.enhanceexperience.tetriseffect
2026-10-05 18:39:56 -04:00
spoopyghosty0 13069db28a Vulkan shim vk_spec_fixes (per game): depth images get TRANSFER_DST (not transient ones), Qualcomm shader-resolve subpasses lose their invalid depth resolve; found with the validation layer in Into The Radius 2 2026-10-05 18:19:11 -04:00
spoopyghosty0 7058105056 Launch tests wait for a first boot after an APK change (agent v54: Lepton's transient 'is not a running context' stopped them); Vulkan shim vk_validation (diagnostics: adds Khronos' validation layer, bundled in a test APK, to the game's instance; a global debug.vulkan.layers property kills Lepton's container) 2026-10-05 17:59:03 -04:00
github-actions[bot] df5b949f1a catalog: com.enhanceexperience.tetriseffect (from #45) 2026-10-05 21:57:47 +00:00
github-actions[bot] 3929ff0a8b catalog: com.camouflaj.salmon (from #47) 2026-10-05 21:57:46 +00:00
github-actions[bot] 4910440f56 catalog: com.resolutiongames.abvriop.santacruz (from #46) 2026-10-05 21:57:44 +00:00
spoopyghosty0 bda9045be6 Into The Radius 2: load only Valve's foveation layer (VALVE_rpo removed the game's fog; owner-verified), notes on the remaining pop-in 2026-10-05 17:32:58 -04:00
spoopyghosty0 a7890d46de QuestCraft works: catalog status works (owner-verified 2026-10-05; LIBGL_NOERROR + frame.ltw_depth) 2026-10-05 17:31:35 -04:00
spoopyghosty0 50ab3eb341 frame.ltw_depth: Minecraft launchers' LTW (QuestCraft) loads OpenGL ES through libfpg.so (native/glshim/eglfmt.c), which turns desktop GL_DEPTH_COMPONENT32 into OpenGL ES depth formats; the Frame's Mesa rejected it, so the depth textures never existed and every framebuffer was incomplete (black picture) 2026-10-05 17:22:52 -04:00
spoopyghosty0 4313b52792 QuestCraft: LIBGL_NOERROR for LTW (Lepton env) gets Minecraft past its GL error 1282 at start (the picture is black next, under investigation); notes on ITR2's popping tests (vk_query_slots and Valve's FDM layer ruled out) 2026-10-05 17:09:33 -04:00
spoopyghosty0 4f9ecf4801 WiiCompiled: notes on "Start straight in VR" (owner-verified: opens in VR without the launcher window; off by default because it skips the launcher's import) 2026-10-05 16:46:12 -04:00
spoopyghosty0 9a5efa28f5 Translation template for the vk_query_slots texts 2026-10-05 16:38:30 -04:00
spoopyghosty0 cf900cd9d4 vk_query_slots: in the Game settings dialog (switch, Troubleshooting; Unreal Vulkan games), 1 = on; fix the settings-dialog test and the translation template 2026-10-05 16:37:10 -04:00
spoopyghosty0 ef21b33ca2 Vulkan shim: vk_query_slots (per game) gives occlusion queries one slot per eye; in multiview passes the Frame's Mesa driver writes the second eye's zero result into the next query, culling visible objects (Into The Radius 2's popping models; not yet confirmed in a headset). Sidebar: Sleep / Restart / Shut down below the Frame card 2026-10-05 16:30:07 -04:00
spoopyghosty0 799f1bd9f1 frame.start_activity (opt-in): start an app's VR activity directly instead of its 2D launcher (WiiCompiled's flat window stayed in view after the VR part started); per-element manifest edit, VR activity from the original APK's analysis (OVRPort gives every MAIN activity LAUNCHER + VR); notes on QuestCraft (Minecraft stops at GL error 1282) and ITR2 pop-in 2026-10-05 16:20:31 -04:00
spoopyghosty0 44a056095d Dashboard worker (agent v53) leaves a dashboard the player opened with the controller alone (v52 closed it 60 ms after each press, the game stayed paused); Into The Radius 2: focus_hold up to 2.5 s (the Frame dropped focus for 0.4 s and 1.0 s and Unreal paused each time), notes from the headset test 2026-10-05 15:58:50 -04:00
spoopyghosty0 6037b13e88 Dashboard at game start (agent v52): watch from the game's first submitted frame instead of the first pacing summary, which came ~8 s after Steam's "Resume game" menu (seen with Into The Radius 2); incremental log reads, 0.5 s checks 2026-10-05 15:46:54 -04:00
spoopyghosty0 c3a34ace99 Files, Screenshots and Library: right-click menus (Files and Screenshots; on one of several selected items they act on the whole selection) and click-and-drag multi-select in all three; selection bars moved below the lists so they don't shift items mid-drag; the Files row Download button works again (Flet never awaited it); ui_smoke --gestures drives real mouse drags and right-clicks 2026-10-05 15:43:06 -04:00
spoopyghosty0 05843633a7 Proton: the stable one is the default again (agent v51), Experimental suggested when a PC VR game fails; USB setup: "OR" between the two setup buttons and a Developer Mode pop-up first; tr_n crash in the catalog toast/Settings fixed; no "configs updated" toast on the first download 2026-10-05 14:55:23 -04:00
spoopyghosty0 5198f704e9 Game configs update without a release: installed apps fetch catalog/games from GitHub main every 6 h (one API call + changed files only; background, cache-only loading; Settings → Data: last check, Check now, off switch; frameport catalog-update). Configs that need a newer FramePort (unknown patch, adapter setting or field, or min_app above this version) are skipped 2026-10-05 14:31:21 -04:00
spoopyghosty0 eeee7d2b84 Merge pull request #43 from GreySyntax/patch-1
Add missing macOS file entitlement
2026-10-05 14:28:52 -04:00
spoopyghosty0 772c26d91a Connect with a USB cable: wizard "Set up with a USB cable" (live cable detection; setup command over the cable via the Frame's fixed PC address 10.86.200.234; connects right away when already set up), discovered Frames de-duplicated by SSH host key preferring USB > Frame hotspot > network, USB check fixes. Verified on the device: NCM driver-free on Windows 11, DHCP from the Frame, Frame->PC over the cable, the real setup end to end over USB, 36.9 vs 11.3 MB/s, re-finding a lost address 2026-10-05 14:24:48 -04:00
spoopyghosty0 db0a78ccc3 FAQ: how to lay out games with OBB files (data folder named after the package, one folder per game) 2026-10-05 13:58:43 -04:00
spoopyghosty0 01d764e05c scripts/usb_autotest.py: one autonomous USB-cable test (Windows adapters/driver/USB class via powershell.exe from WSL, the Frame's gadget units and NetworkManager setup, Frame -> PC over the cable, SSH + upload speed over USB vs Wi-Fi), Markdown report 2026-10-05 13:52:32 -04:00
spoopyghosty0 0c5c1638ed USB cable link check: agent v50 usb_link (usb0 state/addresses, gadget functions, USB speed, DHCP from the Frame, sshd) and frameport frame usb-check (this PC's address on it, SSH over the cable with the same host key, upload speed vs the normal link) — for deciding on a USB connection option in the setup wizard 2026-10-05 13:41:41 -04:00
spoopyghosty0 a49cfb0b57 PC VR games default to Proton Experimental (agent v49), with Stable one click away: Customize shows the Proton version as a dropdown, and a launch test that fails on Experimental suggests "Try the stable Proton and reinstall". Installing asks again for the runtime Steam names only after Proton is installed 2026-10-05 13:35:26 -04:00
Jordan 0f975d2233 Add missing macOS file entitlement
Without this entitlement the app is unable to show the file picker dialogue.
2026-10-05 16:27:38 +01:00
spoopyghosty0 ccff9ab486 FramePort 0.9.1 2026-10-05 08:42:45 -04:00
spoopyghosty0 f2cf7db507 Dev builds on demand: CI "Run workflow" (dev ticked, optional notes for testers) publishes the rolling dev pre-release with version <next patch>.dev<run>; Settings → Updates → "Install the latest dev build…" installs it like an update (automatic checks still ignore it; the next release is offered normally) 2026-10-05 08:30:05 -04:00
spoopyghosty0 2f740bbb41 Agent v48: incomplete deployment records (no base/appid) no longer break every connection with KeyError: 'base' (GitHub #40); the app logs unexpected connect errors with their traceback 2026-10-05 08:21:21 -04:00
spoopyghosty0 1462d3d471 FramePort 0.9.0 2026-10-05 00:10:17 -04:00
spoopyghosty0 22d10c1ff0 Merge the Linux apps GUI (Add games entries, Linux badge/filter, game page summary + missing-library warning, Frame-only actions, change program) 2026-10-05 00:09:42 -04:00
spoopyghosty0 8b9657b2e6 Frame power bar in the sidebar: Sleep / Restart / Shut down above the Frame card, each with a confirmation (agent v47 power: a user timer runs systemctl, since logind only allows it from the user's units). Restart verified on the device. ui_smoke: configurable port, power confirmation step 2026-10-05 00:07:16 -04:00
spoopyghosty0 bc6f6b7fe2 GUI for native arm64 Linux apps (GitHub #31): Add games -> Add a Linux app (arm64)... / folder (background job, opens the page), Linux badge + library platform filter, game page without recipe/patches (program + Change..., AppImage, OpenXR, source; missing-libraries callout), menus without conversion/recipe actions, Frame-only installs, Steam tags "Linux app on Frame"/"Linux", no Quest/Rift twins; safe local-file deletion for lone AppImages; Linux recipes don't follow the catalog; ui_smoke --linux 2026-10-05 00:06:12 -04:00
spoopyghosty0 8f3c8b33ba README: Screenshots tab section with images 2026-10-04 23:57:22 -04:00
spoopyghosty0 8187c79d17 UI smoke: sample screenshots from the games' store screenshots (docs images of the Screenshots tab) 2026-10-04 23:54:59 -04:00
spoopyghosty0 2ecf7f8624 Merge the Screenshots tab (agent list/delete_screenshots, play-session log for attribution, PC cache + download, GUI tab); agent v46 2026-10-04 23:50:48 -04:00
spoopyghosty0 6200662bc7 Linux apps on the PC side (GitHub #31): analysis/linux.py (AppImage/folder/archive, aarch64 check with a clear x86_64 refusal, program ranking, OpenXR detection from the program and its own libraries), library kind "linux", install plan + upload, frameport add-linux. Verified end to end on the device (FramePort's arm64 build: upload, art, library check, Steam shortcut, launch test RUNNING, uninstall) 2026-10-04 23:49:42 -04:00
spoopyghosty0 d2c72264be Screenshots tab: Steam screenshots on the Frame, matched to games by play session
Agent v45: list_screenshots (screenshots.vdf + folders, every account; the Frame files headset shots under SteamVR
250820, so launch.sh now logs start/end to <anchor>/plays.log and upgrade_launchers adds it to existing launchers) and
delete_screenshots (only images in userdata/<id>/760/remote/<appid>/screenshots, links refused, vdf left to Steam).
PC: install/screenshots.py (thumbnail/full-image cache under screenshots-cache/<frame>, cancellable download).
GUI: Screenshots nav item (grid by day, game filter, viewer with prev/next, multi-select download/delete), game menu
entry; ui_smoke --fake-frame sample shots.
2026-10-04 23:47:08 -04:00
spoopyghosty0 f37f7be9c7 Agent: install arm64 Linux apps (GitHub #31; agent v45): prepare/finalize_linux (AppImages extracted once, missing shared libraries reported via ldd of the app's programs), launcher with the exit watchdog, Steam tag "Linux app on Frame", launch test, stop, uninstall. Verified on the device with an AppImage (Venera: libwebkit2gtk missing, reported) and a tar build (FramePort arm64: runs from Steam, Exit game, uninstall). The app no longer replaces a newer agent on the Frame (an older FramePort kept downgrading it) 2026-10-04 23:43:32 -04:00
spoopyghosty0 d05dd27971 Into The Radius 2 recipe: works with issues (flickering textures reported; space warp turned off with hide_space_warp, not yet confirmed in a headset)
Closes #35
2026-10-04 23:34:01 -04:00
spoopyghosty0 fd478f4c70 Notes: space warp findings (Into The Radius 2), PR #34, heuristics evaluation baseline 2026-10-04 23:28:06 -04:00
spoopyghosty0 d834ffac42 Heuristics: suggest AC Nexus's 90 Hz no-AppSW patch whenever it applies; Unreal Engine 5 games with Meta's plugin show hide_space_warp as an option (off) with the flicker hint 2026-10-04 23:27:14 -04:00
spoopyghosty0 3e11175001 Audio metadata fix: look for Meta's audio library at most once a second and stop once a different build was found (it rescanned every loaded library on every xrPollEvent in games without it) 2026-10-04 23:26:41 -04:00
spoopyghosty0 85a11061d0 Merge PR #34: Meta XR Audio metadata lifetime fix for Batman: Arkham Shadow smoke bombs (Lucas-Mathieu); adapters rebuilt here 2026-10-04 23:26:27 -04:00
spoopyghosty0 e26cb8b0db FrameBridge hide_space_warp (per game, off by default): hides XR_FB_space_warp and removes space warp info from the eye images; for games whose picture flickers with Application SpaceWarp (Into The Radius 2 under test; OVRPort's patch_disable_space_warp doesn't reach UE5) 2026-10-04 23:22:27 -04:00
spoopyghosty0 208d7bb4dd Close SteamVR's dashboard once a FramePort game shows its first VR frames (it was open at every start, also over Lepton's 2D launcher): launch.sh starts the agent's dashboard helper, which uses Steam's UI (CEF devtools); existing launchers get it in place (agent v44) 2026-10-04 23:08:41 -04:00
spoopyghosty0 cf1a2c9181 launch.sh ends the game when Steam's reaper is gone (GitHub #36: Exit game left Lepton running); existing launchers get the watchdog in place (agent v44); PLAYBOOK rows for the Steam library fallback and Exit game 2026-10-04 23:03:02 -04:00
spoopyghosty0 ba9ccc3606 FramePort 0.8.0 2026-10-04 21:39:55 -04:00
spoopyghosty0 83a614d645 Steam library fallback (GitHub #21/#30): when the Frame's Steam doesn't know FramePort's shortcut (Play: AppError_9), the game is added through Steam's devkit interface, live and without a restart, with its art; uninstall/purge remove it. Play reads Steam's AppError lines; diagnostics include Steam's shortcut log and devkit games (agent v43) 2026-10-04 21:38:50 -04:00
spoopyghosty0 5734c1fdee Use your own artwork: choose an image file for a game's cover, wide cover, banner, logo or icon (game menu, or from Find artwork), checked and stored as the user's pick so automatic fetches keep it 2026-10-04 20:31:09 -04:00
spoopyghosty0 af791a45b4 FramePort 0.7.2 2026-10-04 20:23:58 -04:00
spoopyghosty0 11c8802b07 Remember the window position and maximized state (GitHub #32); diagnostics for Steam refusing FramePort's games (GitHub #21/#30): Play reports what Steam's log says about the launch, diagnostics include the Steam library state and Steam's launch log lines (agent v42) 2026-10-04 20:22:47 -04:00
Lucas-Mathieu 70d519a5a9 Fix Meta XR Audio metadata lifetime during Batman smoke effects 2026-10-05 01:50:57 +02:00
spoopyghosty0 4e00c88949 FramePort 0.7.1 2026-10-04 19:24:49 -04:00
spoopyghosty0 1b62d643f3 Notes: language packs verified with Deadpool VR (English dialogue with the patch on) 2026-10-04 19:23:33 -04:00
spoopyghosty0 6bd4eb523f One job queue per process (Flet builds a new app per window session: an old session's job ran unseen and the same game was built twice at once in one work folder, both failed) and one build per game at a time 2026-10-04 19:23:32 -04:00
spoopyghosty0 d22123c657 Language packs: lint (line length, imports) 2026-10-04 19:23:32 -04:00
spoopyghosty0 0137cd993b Language packs: ship libfp_langpack.so (built here), drop the dispatcher's late asset-list answer once we answered after the timeout (one answer per request), per-thread skip list, and games already in a library get their packs listed after an app update 2026-10-04 19:23:32 -04:00
yzfsoldier 7b8e7c2c5d Opt-in frame.langpacks: serve <tag>.lang language packs from the game's files (PR #20)
Some Quest games ship voice-over languages as <tag>.lang files and ask the Meta Platform SDK for them; overport's
platform loader answers with nothing, so every language but the built-in one stays greyed out. libfp_langpack.so
answers the language-pack and asset-file calls from the packs already on the device (Metadata = the game's
versionName, the /storage/emulated/0 path spelling Unreal uses). Tested in the headset with Deadpool VR (German
dialogue), AC Nexus and Asgard's Wrath 2.
2026-10-04 19:23:29 -04:00
spoopyghosty0 990331e5b6 WiiCompiled VR recipe: how to add a game (upload the .wcgame to its Import folder with the Files tab) 2026-10-04 18:32:29 -04:00
spoopyghosty0 56b370f582 WiiCompiled VR recipe: works with issues (no document picker in Lepton: manual .wcgame import; right eye jitters in races, inside the game's own OpenXR path) 2026-10-04 18:29:53 -04:00
spoopyghosty0 ac628cd284 FrameBridge: per-eye diagnostics (eye_debug: submitted vs fresh eye poses, eye-to-eye relation, release timing; also logged to framebridge.log because some games end Lepton's logcat early) and release_wait (wait for the game's GPU work before an image is released; 2 = A/B after 60 s) 2026-10-04 18:24:15 -04:00
spoopyghosty0 c12b2f6992 Steam art: games whose only art is the library's generated cover/banner get the placeholder set again (they got no Steam art at all, e.g. WiiCompiled) 2026-10-04 18:19:03 -04:00
spoopyghosty0 a110e8573f QuestCraft recipe: works with issues (Java runtime missing on first start; Minecraft's graphics then fail with OpenGL error 1282) 2026-10-04 18:11:37 -04:00
spoopyghosty0 4fdeeaf829 FrameBridge emulates Android video panels (XR_KHR_android_surface_swapchain: I Am Monkey's intro, surface_emul); the launcher repairs save folders without group write (SUPERHOT quit at start, agent v41); SUPERHOT (Quest) and I Am Monkey recipes; Lucky's Tale's out-of-memory diagnosis 2026-10-04 18:07:22 -04:00
spoopyghosty0 dbabb37343 FramePort 0.7.0 2026-10-04 17:08:34 -04:00
spoopyghosty0 7afee4bf59 FramePort on the Frame: Play in Desktop Mode says the game will be in the Steam library back in Gaming Mode (was an error: the waiting library update read as 'no answer'); a second request for a game whose library update already waits doesn't start another (agent v39) 2026-10-04 16:53:47 -04:00
spoopyghosty0 7367a35176 Library rescans find new downloads: a folder with a stray APK next to game folders counted as one game (the scan stopped there), and games more than two folders down (a download manager's <library>/data/downloads/<game>/) weren't searched; now 5 levels, collections vs game folders told apart, PC program folders and code checkouts skipped 2026-10-04 16:50:33 -04:00
spoopyghosty0 9948f946c5 Remove from library offers the same 'also delete this game's files on this PC' option (off by default) 2026-10-04 16:39:35 -04:00
spoopyghosty0 3870500972 Uninstall asks whether to also delete the game's files on this PC (off by default): the APK and data folder (or a PC VR game's folder) and FramePort's converted copies, listed with their size; never signing keys or files another library entry uses; the game then leaves the library 2026-10-04 16:36:17 -04:00
spoopyghosty0 a7b02c00ee On the Frame itself the app keeps its data in ~/.local/share/frameport-app: ~/.local/share/frameport is the agent's folder, which its purge removes (with the game signing keys) 2026-10-04 16:31:54 -04:00
spoopyghosty0 09c7bb6ea7 SDL / LÖVE apps start on the Frame (GitHub #24): Lepton's Android has no clipboard service and SDLClipboardHandler's constructor crashed on it; frame.sdl_clipboard skips that one call with an in-place classes.dex edit (apk/dex.py), verified with LÖVE for Android 11.5 (crash without, runs with). Android apps without VR keep every suggested non-VR patch 2026-10-04 16:29:45 -04:00
spoopyghosty0 3761dfd62d FramePort on the Frame itself: on SteamOS ARM64 it remembers 'This Frame' (127.0.0.1) and authorizes its own key (no pairing; Developer Mode for sshd, explained if off). Steam library changes wait while Desktop Mode is open (a Steam restart would end it, and FramePort with it; agent v38). Recipe: Beat Saber co-existence build (#29, without the repack's branding) 2026-10-04 16:17:24 -04:00
spoopyghosty0 f86d9021f9 Steam library fixes (GitHub #4, #21, #27): shortcuts go to every Steam account, the agent waits for Steam's helpers before writing and checks the entries survived Steam's restart (writes once more, else reports it; agent v38); Play's add-to-library repair no longer crashes (TypeError since 0.6.3). Uploads resume after a transient OSError (Windows Errno 22). Recipes: Riven (#26), SUPERHOT VR Rift version (#28) 2026-10-04 16:03:38 -04:00
spoopyghosty0 83e901a682 Accounting+: works with issues (VR starts with frame.unity_oculus_check + the frame-wait shim; stuck at 'press any button' although its OVRInput gets clean input). The shim's input wrappers (logging, input focus, stuck-button release) stay behind INPUT_PROBE (off); per-hand interaction profiles and input counters in layer_debug 2026-10-04 15:50:00 -04:00
spoopyghosty0 246e5fc5ee Accounting+ runs: with the frame-loop shim Unity 2017's built-in Oculus support submits frames (~71 fps in the launch test, was a frozen dashboard); frame.unity_oculus_check is suggested again 2026-10-04 15:03:49 -04:00
spoopyghosty0 17403779cb Accounting+ / Unity 2017 built-in Oculus: native/ovrpshim (libfp_ovrp.so) adds the frame wait Unity's legacy loop never makes (fpov_Update2 = ovrp_WaitToBeginFrame once per frame, then ovrp_Update2); frame.unity_oculus_check renames the lookup in libunity.so and links the shim into libOVRPlugin.so. Still opt-in until a launch test shows frames 2026-10-04 14:58:01 -04:00
spoopyghosty0 0e03e061a4 Recipes FramePort derived (not the user's own) are derived again once after every app update, so new automatic fixes reach games already in a library (e.g. the Vulkan shim for own-engine games); a changed recipe shows Update on Frame 2026-10-04 14:52:26 -04:00
spoopyghosty0 d8cf19fb20 Owner's verdicts: Blade & Sorcery works, BattleGlide works, Myst and I Am Cat work with issues, Roblox unsupported; Myst keeps application space warp (turning it off didn't help). PLAYBOOK: symptom rows and debugging techniques from these sessions (headset-only failures, linker log via LEPTON_GFXRECON_FP_PROPS, Unity's own tombstone, wear-sensor focus losses in vrserver.txt, inlined getters, catalog YAML) 2026-10-04 14:43:49 -04:00
spoopyghosty0 7cd9a38eaf Headset round 3: Blade & Sorcery's freezes are the headset's wear sensor flickering off while worn (SteamVR 'HMD off' 0.5-2 s), which only this game pauses on: new adapter setting focus_hold_ms (default 1000; 2500 in its recipe). Installs no longer restart Steam when the game's shortcut is unchanged (a reinstall ended a game being played), and wait while a game runs when Steam has to restart (agent v37). frame.vk_sanitize also covers own-engine libraries that load libvulkan.so by name (Roblox's crash is on Fossilize's recording thread). Myst: app space warp off (object glitches). frame.unity_oculus_check is opt-in (Unity 2017's frame loop never waits: dashboard freeze). focus_hold: 1 s focused / 1 s dips by default 2026-10-04 14:15:50 -04:00
spoopyghosty0 4f3593192f Recipes from the second headset round: BattleGlide works (focus_hold), Myst works with minor glitches (sync_guard confirmed), Blade & Sorcery still jumps/freezes now and then. GAMES.md is generated from the repo's recipes only (a local user catalog hid Myst), and a test parses every catalog file (a broken one was skipped silently) 2026-10-04 12:03:53 -04:00
spoopyghosty0 974426d1d0 Headset round (2026-10-04): frame.unity_oculus_check (Unity 2017-2018 built-in Oculus starts VR only with Meta's com.oculus.systemactivities; Accounting+ now creates its OpenXR instance instead of running as a hidden 2D app); adapter sync_guard (the Frame runtime's xrSyncActions race right after focus, Myst); recipes: Myst, BattleGlide and Blade & Sorcery: Nomad (focus_hold for the Frame's brief focus dips) as works with issues, Roblox and BONELAB unsupported with what was found; triage + PLAYBOOK rows 2026-10-04 11:45:52 -04:00
spoopyghosty0 b7a0e0cb5b Notes: device results for the requested games (BONELAB, Roblox, Accounting+ findings) 2026-10-04 11:14:57 -04:00
spoopyghosty0 38edc26092 Cpp2IL: a build it can't read (e.g. Unity 2017) is cached as such, so each Unity patch doesn't run it again, and the error names Cpp2IL's exception instead of a stack trace; the controller-profile triage line no longer suggests profile_remap (it's on by default) 2026-10-04 11:14:43 -04:00
spoopyghosty0 e96e25bade Controller profiles (0.7.0 D): the adapter suggests bindings for Meta's newer Touch profiles (Touch Plus/Pro), which the Frame's runtime rejects, again as oculus/touch_controller (setting profile_remap, default on; triage info signature). unity_no_msaa: games with several MSAA quality levels failed ('bytes not found in place'), and pre-2019 Unity names the field blendWeights 2026-10-04 10:27:53 -04:00
spoopyghosty0 67c991ca4f Fixes from user reports, round 2: VR4 campaign hang (one shader reads an uninitialized loop counter; the Vulkan shim's new vk_shader_fix setting inserts the zeroing stores, matched by size + SHA-256, from #10's capture); I Am Cat multipass (the getter is inlined: the field read in OculusLoader.Initialize is rewritten, verified on a Frame); builds remember their recipe (recipe_fp, Patch.revision) so changed recipes show Update on Frame; a Frame that got a new address is found again by its SSH host key; packaged apps show library artwork (#16); diagnostics include this boot's kernel log; the Game settings dialog keeps text settings; recipes from #13, #14, #15, #17 2026-10-04 10:21:30 -04:00
spoopyghosty0 d2017194f3 Catalog recipes reach games already in the library: recipes remember the catalog entry they came from (catalog_rev) and are derived again when it changes (never the user's own edits); a maintained entry updated after the user's shared copy wins. Recipes: I Am Cat (issues: frame.unity_multipass), Lucky's Tale (issues: frame.unity_runtime_msaa_off), VR4 works with the no-ForceQuit build 2026-10-04 01:31:16 -04:00
spoopyghosty0 7a11706b3a FramePort 0.6.3: Unity patches frame.unity_runtime_msaa_off (OVRManager turns 4x MSAA on at runtime: Lucky's Tale restarted the headset, #9) and frame.unity_multipass (Oculus XR Plugin multiview: I Am Cat's grey right eye, #8), sharing one Cpp2IL run per build; triage signature for runtime MSAA; VR4 installs the no-ForceQuit build (#10) 2026-10-04 01:22:47 -04:00
spoopyghosty0 76d4390b19 Steam library entries (issues #4, #5: 'Game configuration unavailable', no shortcuts): agent v35 adds shortcuts for the signed-in Steam account (loginusers.vdf), else every account, instead of failing when the Frame has several; Play launches the shortcut's own id and says when a game isn't in the library, and the app then adds it and starts the game; an install whose library entry isn't confirmed says so. Triage: OVRPlugin's routine 'Unavailable OpenXR extension: XR_FB_scene' no longer suggests scene emulation 2026-10-04 01:10:52 -04:00
spoopyghosty0 2022d9986a Catalog: VR4 keeps its package title (com.Armature.VR4; the store name stays in source_hint for matching dump folders) 2026-10-04 00:54:16 -04:00
spoopyghosty0 9ff7edf93b Catalog: working configs from issues #1 (Resident Evil 4, package com.Armature.VR4: works with issues), #3 (Cook-Out), #6 (Beat Saber), #11 (Job Simulator), #12 (Dinosaur Island); games list regenerated. catalog_from_issue: 'device' is a checked list field, and FramePort patch ids must exist 2026-10-04 00:52:39 -04:00
spoopyghosty0 a5722b50a0 Windows games without VR (Reddit request): a game folder added with 'Add one game folder…' that has no VR runtime becomes a flat Windows game: only the Proton patches, a launcher without SteamGameId (Proton sets up no VR), a non-VR Steam shortcut (OpenVR=0, tag 'Windows game on Frame'), labels 'Windows game (Proton)'; no 'Play on this PC' 2026-10-03 19:38:23 -04:00
spoopyghosty0 0a13ca72a2 Frame crash detection: agent v34 reports the boot id, whether the previous boot shut down cleanly (journal) and the FramePort game launched last before it; the app compares with the last boot it saw and, after an unclean restart soon after a game started, says so with Report a problem. Diagnostics include the previous boot's errors and kernel warnings (GPU resets, OOM) 2026-10-03 19:33:37 -04:00
spoopyghosty0 c53d754007 FramePort 0.6.2 2026-10-03 19:29:24 -04:00
spoopyghosty0 a1662da17d Connecting a new Frame (Reddit feedback): a PC without SSH keys made paramiko end the key attempt with 'No authentication methods available' (SSHException), which stopped the loop before the password was tried and showed that raw message; now it's a failed login like any other, and the final error (FrameNotPaired) says to run the first-time setup or that the password was refused. Wizard: first-time setup is step 1, a 'not set up yet' callout with the setup button after such a failure. Failed installs/tests offer Report a problem. README/GAMES/CONTRIBUTING: share-a-config and report-a-problem links 2026-10-03 19:02:31 -04:00
spoopyghosty0 0141bad259 Desktop on the Steam Frame: SteamVR dashboard → Launch a program → Desktop, then System → Konsole (the Steam Deck's Power → Switch to Desktop doesn't apply) — README, INSTALL, setup wizard, CLI, bootstrap 2026-10-03 18:12:12 -04:00
spoopyghosty0 6ed95684dc FramePort 0.6.1: Linux ARM64 build (CI ubuntu-22.04-arm, PyInstaller one-folder fallback; the updater picks FramePort-linux-arm64.tar.gz on ARM); tested games list docs/GAMES.md generated from the catalog (scripts/compat_list.py) 2026-10-03 12:05:59 -04:00
spoopyghosty0 a6ca8385a9 COMPATIBILITY: no game counts (they change often); point to the catalog recipes 2026-10-03 11:38:56 -04:00
spoopyghosty0 210410f125 Catalog: Stremio VR works (confirmed by the owner with frame.unity_text_input + device.text_input_window); compatibility count 28/5/6 2026-10-03 11:37:59 -04:00
spoopyghosty0 7e2502a552 FramePort 0.6.0: Type on Frame screenshot in the README; sidebar keyboard icon compact next to the Frame name; docs: the shown app window is listed as Gamescope 2026-10-03 10:44:17 -04:00
spoopyghosty0 a57d89e874 README: highlight Type on Frame (second feature bullet + its own section) 2026-10-03 10:36:03 -04:00
spoopyghosty0 aade29982f Docs: Typing on the Frame (INSTALL), README feature, PLAYBOOK row, FRAME_RUNTIME/CLAUDE.md text-input facts; catalog count 39 2026-10-03 10:34:58 -04:00
spoopyghosty0 d94cab6048 Unity text fields work on the Frame: frame.unity_text_input finds TMP_InputField/uGUI InputField keyboard methods per game with Cpp2IL (downloaded on first use, cached per libil2cpp) and makes them edit in place; device.text_input_window shows the Android window so Steam's keyboard / Type on Frame reach it. Analysis records text_fields + unity_version; catalog recipes can list device toggles; Stremio VR recipe; 'Analyze again' game action 2026-10-03 10:33:47 -04:00
spoopyghosty0 f17fdbf271 Type on Frame: this computer's keyboard becomes a keyboard on the Frame (agent v33 _keyboard session: Linux uinput virtual keyboard, no root; keys streamed live over one SSH channel, released when it closes). Dialog with live keys + paste; entry points on the Frame page, game menus and the sidebar Frame card 2026-10-03 10:22:33 -04:00
spoopyghosty0 fb70c09d72 CLAUDE.md: Lepton intercepts every VIEW intent with data (companion-app hand-offs like Stremio → 4XVR can't work) 2026-10-03 08:56:27 -04:00
spoopyghosty0 69bf2700e1 Sidebar: Frame battery as an icon + percentage next to the name (level bars, charging/alert icons, tooltip) instead of a suffix that wrapped 2026-10-03 08:35:09 -04:00
spoopyghosty0 0b28da5521 Battery: 'charging' means plugged in and the gauge not draining (a weak charger can supply less than the Frame uses; the Frame reports Discharging briefly after boot); sidebar says 'battery N %' (the font has no battery emoji) 2026-10-03 08:33:01 -04:00
spoopyghosty0 9e9a4c0f6c Frame battery: level in the sidebar and on the Frame page (agent v32 battery_state/battery); during installs on battery power FramePort warns at 30 %, pauses the queue at 15 % (instead of the Frame switching itself off mid-upload) and continues when it's plugged in or back at 25 % (ui/battery.py) 2026-10-03 08:29:23 -04:00
spoopyghosty0 bb3f6b9e7c Release bundles: ship the Frame agent's source (fixes #2). flet build compiles every .py of the app to .pyc, bundled data included, so the agent couldn't be uploaded and connecting failed. Bundles carry frameport_agent.py.txt as well (paths.agent_file reads either); scripts/package.py fails a build whose bundle lacks the source 2026-10-03 08:18:32 -04:00
spoopyghosty0 dc7533e4e1 Add AI Usage Notice 2026-10-03 08:16:53 -04:00
spoopyghosty0 3660167bd8 Adjust README wording 2026-10-03 08:12:20 -04:00
spoopyghosty0 6a47fad8f7 README/INSTALL: step-by-step setup command for non-technical users (Desktop mode, Konsole, typing it, what happens next); Steam Frame badge instead of the status badge 2026-10-02 23:40:14 -04:00
spoopyghosty0 0f8062f881 README: short and to the point (badges, features, quick start, links); details moved to docs/FRAME_SETUP.md (what setup changes, networks and firewalls), docs/COMPATIBILITY.md, credits table to docs/ARCHITECTURE.md, game page screenshots to docs/INSTALL.md 2026-10-02 23:14:29 -04:00
spoopyghosty0 65369f154c Release notes: a short install footer (packaging/release-footer.md) instead of all of docs/INSTALL.md from First launch; the update dialog shows these notes 2026-10-02 23:07:03 -04:00
spoopyghosty0 aefb5adc07 FramePort 0.5.0
Setup without root or password: bootstrap.sh turns Developer Mode on itself (Valve's steamos-devkit-mode helper,
config.vdf set with Steam stopped) and finishes as a user unit, since Desktop Mode is a nested Plasma inside
steam.service (stopping Steam ends it; systemd-run needs the real user bus). Shorter setup command
(curl -fsS <ip>:8765/<code> | bash). Valve's devkit pairing (POST :32000/register, ssh-rsa key, Settings → Developer
→ Pair new host) as a fallback that needs no connection into the PC. Firewall handling: temporary Hyper-V rule on WSL
(one UAC prompt, removed after setup), per-OS hints when nothing reaches the setup server. Flet updates serialized
(a dialog shown during a scan redraw never closed). Setup command survives page redraws. Uninstall: removes Lepton's
overlayfs work dirs (mode 000) and stale shortcuts (agent v31). Tests no longer touch the real data folder. README:
highlights, what the setup changes on the Frame, network and firewalls.
2026-10-02 22:53:10 -04:00
spoopyghosty0 5603edeef7 FramePort 0.4.0 2026-10-02 19:33:58 -04:00
spoopyghosty0 5c47185938 CLAUDE.md: queue resume verified on the device 2026-10-02 19:25:31 -04:00
spoopyghosty0 fefdc19cac Library cards without key= (Flet freezes keyed controls: hovering a card crashed the app with 'Frozen control cannot be updated'); Activity: progress ticks update only the progress controls and the log when it grew, instead of re-diffing the whole panel 5×/s (sluggish UI during installs) 2026-10-02 19:19:21 -04:00
spoopyghosty0 db6ccece32 Library cards are keyed and the grid holds only the matches, in order (a search could hide a matching game and name sorting looked wrong); game page keeps its scroll position when redrawn; Activity: the running job scrolls in its own area, its log keeps its position and follows new lines only while at the bottom; the search clear icon no longer pushes the text off-centre 2026-10-02 19:12:11 -04:00
spoopyghosty0 59018cb396 CLAUDE.md: round-2 notes 2026-10-02 18:59:45 -04:00
spoopyghosty0 70216de397 Docs: new screenshots (library, game, patches, Game settings, Steam Frame, Files), README and INSTALL cover Game settings, queue waiting/wake lock, temporary converted copies, 2D apps, sharing configs, contributing translations 2026-10-02 18:59:09 -04:00
spoopyghosty0 bef61563d5 Already converted games still get their alternate (no-ForceQuit) build: the saved copy, else one OVRPort run for the alternate patches; Nano's built-in recipe uses the no-ForceQuit build (owner-confirmed working) 2026-10-02 18:57:58 -04:00
spoopyghosty0 1b728d7c75 Converted APKs are temporary: removed after the game is installed on the Frame (Settings → Installing: keep them, or remove all now); installs convert again when the copy is gone; the user's own APKs are never touched 2026-10-02 18:55:40 -04:00
spoopyghosty0 60cde5f846 Already converted APKs aren't converted again (a second OVRPort run replaced the platform loader and dropped its link to the Meta stand-ins: Wallace & Gromit and Espire 2 crashed with 'cannot locate symbol ovr_...'); only the Steam Frame patches are applied, the alternate build comes from the saved copy; the stand-ins patch relinks an unlinked libovrstubs.so and the symbol check only counts linked libraries 2026-10-02 18:53:46 -04:00
spoopyghosty0 c3a63bbd85 Picking a Meta store result uses the picture the picker showed (the store service by package served a 'dogfooding' placeholder for some games, e.g. Asgard's Wrath 2, so picks never changed the art); the service only adds logo and icon 2026-10-02 18:44:48 -04:00
spoopyghosty0 bbe76ab888 Customize: every patch described in plain words with a plain reason (Standard / From the tested recipe / Turned on by you …); 'Show technical details' (remembered) adds ids, exact effects, exact reasons and parameters 2026-10-02 18:42:02 -04:00
spoopyghosty0 b89e48cec0 Untested games invite sharing their recipe (works / has issues / doesn't run, Not now) on the game page and after a passing launch test; shared or dismissed games aren't asked again 2026-10-02 18:38:25 -04:00
spoopyghosty0 dc020a2cb7 Install file browser explains the known folders (shader cache, saves, the game, Steam art, rollback copy, log) 2026-10-02 18:36:37 -04:00
spoopyghosty0 cc3febfae4 2D Android apps get artwork in FramePort: the APK's launcher icon (manifest icon first, any bitmap density) and a generated cover/banner when no store art exists (scan time + one background backfill); one icon extractor for FramePort and Steam 2026-10-02 18:35:15 -04:00
spoopyghosty0 e729f3f4bc Picked artwork stays: automatic art fetches only fill missing kinds and skip picked art (a pick without an icon was replaced by the store art at the next install); the game page reminds when the Frame's Steam library shows old art; saving a recipe keeps 'works with issues' (it always saved 'works'), the share dialog starts from the game's status 2026-10-02 18:30:29 -04:00
spoopyghosty0 2fecfbf6ea Install queue waits for the Frame when it drops off the network (job back at the front, queue paused, reconnect every 10 s, continues where uploads stopped); wake lock on the Frame while jobs use it (agent v30 keep_awake: idle+sleep inhibitor, idle-only fallback, expires by itself); free-space check before queueing a batch 2026-10-02 18:23:06 -04:00
spoopyghosty0 6e0bb8ee59 Plain explanations for common failures (Frame offline/asleep, busy connection, disk full, game running, Steam not responding, damaged APK or upload) in the GUI and CLI; the exact error stays in the job log 2026-10-02 18:18:03 -04:00
spoopyghosty0 26679114ed Library search has an X to clear it; Settings: text above buttons in Problems/Remove (no squeeze); the help icon sits right after a switch label; translation guide in CONTRIBUTING; PyInstaller bundles include the translations 2026-10-02 18:15:57 -04:00
spoopyghosty0 b8e49a3419 No release-group names in the code: release tags are recognised by their form (trailing ' -TAG', [..] notes), same titles for every real folder; OVRPort spelled consistently in user-visible texts (patch titles from OVRPort's strings only for patches FramePort doesn't describe) 2026-10-02 18:12:38 -04:00
spoopyghosty0 f196cf556d Game settings dialog replaces the raw adapter fields: plain labels, switches/sliders/choices, only settings that matter for the game (advanced ones on request), saved in the recipe and applied live; shared SFTP channel pool (per-thread channels exhausted the SSH connection: ChannelException 'Connect failed' in Test Proton); switch labels wrap; wording fixes 2026-10-02 17:33:49 -04:00
spoopyghosty0 1b0345b15b Activity: the running job is pinned at the top (with a long queue it was listed after every waiting job, or cut off); waiting jobs are compact rows in queue order with Cancel all 2026-10-02 17:20:01 -04:00
spoopyghosty0 4508608dcf Notifications close themselves (also those with a button: persist=False) and have an X 2026-10-02 17:16:47 -04:00
spoopyghosty0 3e16199e64 Library: the unfinished-installs bar updates on every refresh (Dismiss/Resume didn't hide it until the Library was reopened) 2026-10-02 17:10:00 -04:00
spoopyghosty0 a7fa1c06d7 Install questions: each dialog acts on its first click only (a double click ran the question chain twice: duplicate dialogs whose buttons didn't work), one question chain at a time, closing a dialog = Cancel; dialogs sized to their content; ui_smoke --install-questions 2026-10-02 17:07:13 -04:00
spoopyghosty0 dabd9b2095 Update all: one batch per target, so each question is asked once with a checkbox per game (was one dialog per game); installed games marked "Can't run" are updated too 2026-10-02 16:41:25 -04:00
spoopyghosty0 0774536473 Window opens at 16:10 sized for the UI scale and remembers its size; headers and filters wrap instead of being cut off in a narrow window; card badges wrap instead of overlapping; larger help icons 2026-10-02 16:36:30 -04:00
spoopyghosty0 4a7fe3645c Hiding Android's navigation bar is a patch (device.hide_navbar, on by default for Android apps without VR; migration for existing entries); game page explains 2D apps; patch registry loads safely from several threads 2026-10-02 16:25:01 -04:00
spoopyghosty0 204aa70ada Android apps without VR: Android's navigation bar no longer covers the app (qemu.hw.mainkeys=1 at boot, agent v29); docs: 2D apps verified on the Frame 2026-10-02 16:13:11 -04:00
spoopyghosty0 8bb3df0ec8 Files: the folder path gets its own line (a narrow window squeezed it to one letter per line), buttons wrap; Android apps without VR get Lepton's flat window marker (agent v28) 2026-10-02 16:02:01 -04:00
spoopyghosty0 d9f9695360 Steam placeholder art for apps without artwork (name on colour, with the APK's launcher icon); no store lookups by title for Android apps without VR 2026-10-02 15:51:57 -04:00
spoopyghosty0 d45d391683 Android apps without VR: only patches that can matter are listed (Patch.needs_vr); parity-device --only also matches package ids, --test-only says when no earlier run exists 2026-10-02 15:37:46 -04:00
spoopyghosty0 b0682ee570 Neutral folder examples in docstrings and CLAUDE.md 2026-10-02 14:35:53 -04:00
spoopyghosty0 d1cf305c0a CLI: errors (e.g. an unreachable Frame) are one line on stderr with exit code 1, FRAMEPORT_DEBUG=1 for the traceback; clearer no-match message 2026-10-02 14:34:19 -04:00
spoopyghosty0 d22f416489 Visual review: light text for Material labels and dialog titles, OVRPort tool name in Settings and the tools toast 2026-10-02 14:32:13 -04:00
spoopyghosty0 2dc92a090f CLI: help for every command and option, --frame described once, frame send --dest (--to kept), diag report --message (--text kept), errors on stderr, exit codes documented; INSTALL command-line overview 2026-10-02 14:21:55 -04:00
spoopyghosty0 23a47880e0 Lines within 120 columns everywhere (CI lints without exceptions); community and licence files; docs updated
- reflowed long lines (texts unchanged; generated launcher/PowerShell/README texts byte-identical)
- CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, THIRD_PARTY_NOTICES; pyproject metadata (SPDX licence, authors, urls,
  classifiers, keywords)
- maintainer-only notes moved to a git-ignored CLAUDE.local.md; CLAUDE.md facts updated
- README: what kinds of apps run and how; INSTALL: PC VR and Files wording, new labels
2026-10-02 14:18:41 -04:00
spoopyghosty0 da399ef77a Consistent wording (style guide in docs/STYLE.md), language choice once translations exist
patches not fixes, and not &, GiB everywhere, PC VR / Android instead of Rift where it isn't Oculus-specific, one
label per action (Report a problem…, Update now), OVRPort by name; internal ids no longer wrapped for translation
2026-10-02 14:06:35 -04:00
spoopyghosty0 f0192c0e9d Localisation: GUI, help and patch texts go through tr()/tr_n()
- frameport/i18n.py: tr() (English text as key, JSON translations in locales/<language>.json, English fallback),
  tr_n() plurals, size formatting; language from setting ui.language, loaded before the UI modules
- all GUI texts wrapped (templates with .format(), no f-strings inside tr()); hand-built plurals replaced
- help texts translated on lookup (unknown keys are errors); patch titles, descriptions and reasons translated
  where shown; unused help texts removed
- no decisions based on displayed text: the library's quick action returns a kind, Show more keeps its state,
  Files location names come from ids
- scripts/i18n_extract.py writes locales/template.json (802 texts); tests keep it current and fail on untranslated
  literals in text controls
2026-10-02 13:58:50 -04:00
spoopyghosty0 cad54bb2dd Install-as-is check: an APK without native code passes the 64-bit check 2026-10-02 13:48:16 -04:00
spoopyghosty0 507dd4ca6e Non-Quest Android apps and generic PC VR games
- APK analysis classifies apps (vr_kind: quest, openxr, pico_sdk, wave, android_xr, none) and flags split APKs
- ordinary Android apps (no VR): installed unchanged, or with only the launcher fix and no overport/adapter (a
  signing key is created when overport never made one); Pico/Wave SDK and Android XR apps marked unsupported; x86/
  32-bit-only APKs unsupported
- platform labels by what a game was made for (Quest / Android / Android VR / PC VR, Oculus only when LibOVR);
  neutral folder pickers, help texts and Steam tags (PC shortcut tag FramePort PC VR; the old Rift via Revive tag
  still matched for cleanup)
- PC VR games without Oculus code look up Steam art first
2026-10-02 13:46:49 -04:00
spoopyghosty0 a361cdc84d Agent v27 and smaller fixes
- agent: finalize checks the game data before replacing the installed APK; uninstalling a game removes its Steam
  shortcut with Steam closed (detached worker, like adding); grid art deleted by exact appid; cleanup refuses dot
  folders and the install folder; shortcuts.vdf backups capped at 5
- PC: exact grid art matching when pruning old shortcuts
- activity panel: refreshes serialized; a running job's log updates in place (its Cancel button isn't rebuilt)
- SSH key created private (0600) from the first byte; remote catalog ids validated; None checks in install and
  adapter settings; navigate() follows NAV
- removed unused functions
2026-10-02 13:36:42 -04:00
spoopyghosty0 fa7567503f Render paths: game hero thumbnail made in the background, Frame list read only when frames.json changes, one library read for unfinished installs; a newer library reload supersedes an older one 2026-10-02 13:31:11 -04:00
spoopyghosty0 1c90669eb4 Pairing server: random 64-bit code, stops after pairing, 20 wrong codes or 30 min; Rift launch-mode migration retries games whose folder was missing 2026-10-02 13:29:50 -04:00
spoopyghosty0 942a71dd54 Uninstall can't recreate the data folder, removes only FramePort's files from a custom FRAMEPORT_HOME, confirms the Frame-side removal without re-uploading the agent; timeouts for update commands, ditto and wslpath 2026-10-02 13:28:03 -04:00
spoopyghosty0 e462907c49 Fix races: library.json changes under one lock (atomic edit/update helpers), atomic state files, one SFTP channel per thread, refresh errors don't drop a working connection
- library: RLock across load/modify/save, edit()/update_game()/update_setting(); install records merged atomically
- frames.json, tools/revive state and caches written atomically (paths.write_atomic)
- Frame: per-thread SFTP clients, fresh SSHClient per auth attempt (no leaked transports), default 120 s command
  timeout, agent checked once per connection and uploaded via a unique temp file with the move checked,
  agent(ensure=False)
- app: status refresh keeps the connection when it still works; reconnecting closes the replaced connection
- remote paths quoted with sh_quote; the Proton self-test uses the Frame's home folder
2026-10-02 13:23:53 -04:00
spoopyghosty0 60efbbe7a9 Tooling: ruff (lint + import order) and pytest-timeout; CI lints and tests every push to main
Fixes ruff found: loop variables bound in callbacks, zip(strict=True), clearer names than 'l', unused loop
variables, f-strings instead of % formatting.
2026-10-02 13:19:11 -04:00
spoopyghosty0 321588d94b CLAUDE.md: macOS CI runner notes 2026-10-02 11:55:15 -04:00
spoopyghosty0 b4ae5e0023 CI: macOS bundle on macos-26 (newer Xcode); PyInstaller fallback runs non-interactively 2026-10-02 11:33:13 -04:00
spoopyghosty0 4ba148908a CI: pin the macOS bundle job to macos-15 2026-10-02 11:20:22 -04:00
spoopyghosty0 7af21e17ce Files tab: multi-select (download/delete several) and drag-and-drop uploads (flet-dropzone, packaged app only) 2026-10-02 10:47:35 -04:00
spoopyghosty0 fa3544565a PLAYBOOK: Files tab 2026-10-02 10:13:44 -04:00
spoopyghosty0 f7b59a75b3 Files tab: manage files on the Frame (browse, upload, download, new folder, rename, delete)
Replaces the Send files dialog. Locations: Videos/Downloads/Documents (shared by every Quest game), each installed
game's own storage, the home folder. SFTP over the app's connection; every operation stays inside the chosen
location; Lepton's links in a game's storage are protected. Uploads/downloads are resumable jobs. Tested against
the Frame; ui_smoke --fake-frame serves sample files for the docs screenshot.
2026-10-02 10:13:33 -04:00
spoopyghosty0 58eaab3c19 Library cards: big round Play/Install button on hover, stronger card shadows; ui_smoke --hover, --fake-frame never reaches a real Frame 2026-10-02 09:47:15 -04:00
spoopyghosty0 3d32be1a98 AC Nexus: OVRPort's no-space-warp 90 Hz patch by default (build 207706 only); headset results for OVRPort 1.2.5
- Catalog: patch_ac_nexus_no_appsw_90 for AC Nexus (owner preferred it over 72 Hz and the plain recipe).
- Strict overport patches (one exact game build) are only taken from a catalog recipe where they apply.
- Parity: OVRPort's AC Nexus libil2cpp.so rewrite and the extra recipe patch are expected.
- Test: every bundled catalog YAML loads (a parse error silently dropped a recipe).
2026-10-02 09:23:14 -04:00
spoopyghosty0 8da5a44efb Docs: Library screenshot shows only working games (scrub_library --status) 2026-10-02 09:02:27 -04:00
spoopyghosty0 51f0a5d75c CLAUDE.md: self-update verified end to end on Windows and Linux 2026-10-02 01:22:47 -04:00
spoopyghosty0 b06cc9659b FramePort 0.3.4 2026-10-02 01:11:46 -04:00
spoopyghosty0 bc40325c2d Updater: start the Windows swap script in a hidden console and check it runs; Linux bundle built on Ubuntu 22.04
Found in the end-to-end test (0.3.1 -> 0.3.2): PowerShell started with DETACHED_PROCESS from the packaged app exits
without running the script, so the app quit and nothing was updated. apply() now waits until the script logs that it
runs and raises otherwise. The smoke test uses the same non-waiting launch as the app. The Linux bundle built on
24.04 needed GLib 2.80.
2026-10-02 01:01:37 -04:00
spoopyghosty0 82c2209b6f OVRPort 1.2.5, documentation with screenshots, store description cleanup
- The overport CLI now comes from Android-XR-Bridge/OVRPort (fallback ovrport/app); its four new patches are
  described and shown only where they apply; parity classifies the 1.2.5 differences (VR metadata, config version,
  CLI-added platform compat) as expected: 34/34 at parity.
- README rewritten (purpose, getting started, what works, credits, legal), INSTALL tightened, screenshots in
  docs/images (scripts/scrub_library.py + ui_smoke --docs --fake-frame), Quest2Frame references removed.
- Game page: store descriptions without Markdown/[media] markup; themed labels on all switches.
- `frameport install --apk` installs a given build (headset A/B tests).
2026-10-02 00:32:14 -04:00
525 changed files with 77287 additions and 2381 deletions

No files matched your search

+90 -10
View File
@@ -1,9 +1,19 @@
name: build
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
workflow_dispatch:
inputs:
dev:
description: "Publish the bundles as the dev build (testers: Settings → Updates → Install the latest dev build)"
type: boolean
default: true
notes:
description: "What testers should try (shown before they install it)"
type: string
default: ""
jobs:
test:
@@ -12,10 +22,13 @@ jobs:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.2.0
- run: uv sync --extra dev
- name: Lint
run: uv run ruff check .
- run: uv run pytest -m "not games and not device"
bundle:
needs: test
if: github.event_name != 'push' || startsWith(github.ref, 'refs/tags/v') # pushes to main: tests only
permissions:
contents: read
id-token: write # build provenance attestations (Sigstore)
@@ -31,10 +44,13 @@ jobs:
include:
- os: windows-latest
archive: FramePort-windows-x64.zip
- os: macos-latest
- os: macos-26 # Apple Silicon + Xcode 26 (macos-15's Xcode 16.4 fails a Flutter plugin; macos-latest
# went unassigned on 2026-10-02)
archive: FramePort-macos-arm64.zip
- os: ubuntu-latest
- os: ubuntu-22.04 # oldest supported: the bundle needs the build host's GLib/glibc or newer
archive: FramePort-linux-x64.tar.gz
- os: ubuntu-22.04-arm # Linux ARM64 (same base as x64)
archive: FramePort-linux-arm64.tar.gz
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
@@ -43,11 +59,14 @@ jobs:
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y ninja-build libgtk-3-dev
- run: uv sync --extra dev
- name: Dev build version (next patch + .dev<run number>; not committed)
if: github.event_name == 'workflow_dispatch' && inputs.dev
run: uv run --no-project python scripts/dev_version.py ${{ github.run_number }}
- id: flet
run: uv run python scripts/package.py
continue-on-error: ${{ runner.os == 'macOS' }}
- name: macOS fallback (PyInstaller bundle)
if: runner.os == 'macOS' && steps.flet.outcome == 'failure'
continue-on-error: ${{ runner.os == 'macOS' || runner.arch == 'ARM64' }}
- name: macOS / Linux ARM64 fallback (PyInstaller bundle)
if: (runner.os == 'macOS' || runner.arch == 'ARM64') && steps.flet.outcome == 'failure'
run: uv run --with pyinstaller python scripts/package.py --pyinstaller
# ---- signing: self-signed certificate on Windows, ad-hoc on macOS ----
@@ -77,8 +96,27 @@ jobs:
if: runner.os == 'macOS'
run: |
app=$(find dist -maxdepth 3 -name "*.app" -type d | head -1)
codesign --force --deep --sign - "$app"
# Re-signing replaces the signature, entitlements included: pass them again, or the file picker refuses to
# open ("ENTITLEMENT_NOT_FOUND", GitHub #63). flet build writes them to Release.entitlements; the
# PyInstaller fallback has none, so it gets the same set.
ent=build/flutter/macos/Runner/Release.entitlements
if [ ! -f "$ent" ]; then
ent="$RUNNER_TEMP/FramePort.entitlements"
cat > "$ent" <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.network.client</key><true/>
<key>com.apple.security.network.server</key><true/>
<key>com.apple.security.files.user-selected.read-write</key><true/>
</dict></plist>
EOF
fi
codesign --force --deep --sign - --entitlements "$ent" "$app"
codesign --verify --deep --strict --verbose=2 "$app"
codesign -d --entitlements - "$app" 2>/dev/null | tee /dev/stderr | grep -q "files.user-selected.read-write"
# ---- package (archives keep permissions/symlinks) + provenance ----
- name: Package (Windows)
@@ -90,7 +128,9 @@ jobs:
run: ditto -c -k --keepParent "$(find dist -maxdepth 3 -name '*.app' -type d | head -1)" ${{ matrix.archive }}
- name: Package (Linux)
if: runner.os == 'Linux'
run: tar czf ${{ matrix.archive }} -C dist --transform 's,^linux,FramePort,' linux
run: | # flet build -> dist/linux; the PyInstaller fallback -> dist/FramePort (one folder)
if [ -d dist/linux ]; then tar czf ${{ matrix.archive }} -C dist --transform 's,^linux,FramePort,' linux
else tar czf ${{ matrix.archive }} -C dist FramePort; fi
# self-update with this archive: unpack, verify the layout (+ the signer on Windows), run the real swap script
- name: Update smoke test
run: uv run python scripts/update_smoke.py ${{ matrix.archive }}
@@ -132,10 +172,50 @@ jobs:
git fetch --force origin "refs/tags/${tag}:refs/tags/${tag}"
whatsnew=$(git tag -l --format='%(contents:body)' "$tag")
[ -n "$whatsnew" ] || whatsnew=$(git tag -l --format='%(contents:subject)' "$tag")
{ echo "FramePort ${tag}: Windows (x64), macOS (Apple Silicon) and Linux (x64)."; echo;
{ echo "FramePort ${tag}: Windows (x64), macOS (Apple Silicon) and Linux (x64, ARM64)."; echo;
if [ -n "$whatsnew" ] && [ "$(git cat-file -t "$tag")" = tag ]; then
echo "## What's new"; echo; echo "$whatsnew"; echo; fi
echo "Already have FramePort? It offers this update itself (Library → **Update now**, or \`frameport update\`)."
echo; sed -n '/^## First launch/,$p' docs/INSTALL.md; } > "$notes"
echo "Already have FramePort? It offers this update itself (Library → **Update now**)."
echo; cat packaging/release-footer.md; } > "$notes" # short: the update dialog shows these notes
gh release delete "$tag" --yes 2>/dev/null || true
gh release create "$tag" out/* packaging/FramePort-selfsigned.cer --title "FramePort ${tag}" --notes-file "$notes"
dev-release:
# "Run workflow" with dev ticked: replaces the rolling `dev` pre-release (never shown by the automatic update check;
# testers install it from Settings → Updates). Same assets + SHA256SUMS as a release.
if: github.event_name == 'workflow_dispatch' && inputs.dev
needs: bundle
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: astral-sh/setup-uv@v10.2.0
- id: version
run: echo "version=$(uv run --no-project python scripts/dev_version.py ${{ github.run_number }})" >> "$GITHUB_OUTPUT"
- uses: actions/download-artifact@v8
with:
path: out
merge-multiple: true
- name: Wheel
run: uv build --wheel -o out && ls out
- name: Checksums
run: cd out && sha256sum * > SHA256SUMS.txt && cat SHA256SUMS.txt
- name: Publish the dev build
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
NOTES: ${{ inputs.notes }}
run: |
notes=$(mktemp)
last=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)
{ echo "Dev build **${VERSION}** from commit ${GITHUB_SHA::7} ($(date -u +%Y-%m-%d)). For testing fixes before"
echo "the next release; you get that release as a normal update."; echo
if [ -n "$NOTES" ]; then echo "## Please test"; echo; echo "$NOTES"; echo; fi
if [ -n "$last" ]; then echo "## Changes since ${last}"; echo
git log --no-merges --format='- %s' "${last}..HEAD" | cut -c1-160 | head -40; fi; } > "$notes"
gh release delete dev --yes --cleanup-tag 2>/dev/null || true
gh release create dev out/* packaging/FramePort-selfsigned.cer --prerelease --target "$GITHUB_SHA" \
--title "FramePort dev build ${VERSION}" --notes-file "$notes"
+7
View File
@@ -13,3 +13,10 @@ native/.cache/
native/**/build/
# per-machine Claude Code settings (contain home paths)
.claude/settings.local.json
# maintainer-local notes for Claude Code (accounts, credentials)
CLAUDE.local.md
# outputs of `frameport report` / `parity` / ruff
REPORT.md
.ruff_cache/
.claude/worktrees/
+463 -25
View File
@@ -14,7 +14,45 @@ Read `docs/PLAYBOOK.md` (symptom → fix) before debugging a game, and `docs/FRA
status_row, art_fill, confirm, `update()` = safe update: in Flet 1.0 reading `.page` of an unmounted control
raises), `jobs.py` (background FIFO job queue, one at a time, cancel via Reporter; no Flet), `views/`
(library: search/filters/tags/sort as pure tested helpers; game: hero + one-click install, patches under
"Customize"; frame: device + readiness + installed, or connect wizard; settings; welcome; activity panel).
"Customize"; frame: device + readiness + installed, or connect wizard; files: the Frame's file manager (persistent
like the library; locations = Videos/Downloads/Documents from agent `storage_targets`, each installed Quest game's
storage, the home folder; SFTP via `install/files.py` list_dir/upload/download/make_dir/rename/delete, all
confined to the location by `files.inside`; Lepton's links in a game's storage can't be renamed/deleted; replaced
the "Send files" dialog, game menu → "Add videos & files…" = `go("files", pkg)`; multi-select bar (download/
delete); drag-and-drop from the OS via the `flet-dropzone` extension (Apache-2.0, Flutter `desktop_drop`), which
only a `flet build` bundle contains: `files.dropzone_available()` keeps it out of source runs and the PyInstaller
fallback, which would show an unknown control); screenshots (Steam screenshots on the Frame, `install/screenshots.py`
+ agent v46 `list_screenshots`/`delete_screenshots`: the Frame files every headset shot under SteamVR 250820, so
launch.sh logs `start/end <unix>` to `<anchor>/plays.log` (upgrade_launchers adds it; Proton launchers exec → start
only) and shots are matched by time; thumbnails cached in `<data>/screenshots-cache/<frame>/`, shown by asset URL;
delete leaves screenshots.vdf alone (Steam rewrites it at exit); game menu → "Screenshots" = `go("screenshots",
pkg)`); live view (`views/live.py` + `install/livestream.py`: the Frame's built-in SteamVR "headset view" webcam
(`steamvr-v4l2cam.service` → v4l2loopback "SteamVR" /dev/video99, see docs/FRAME_RUNTIME.md) + the default
output's pulse monitor (sound) → `fp_venc` (`native/venc`, own clean-room V4L2 driver of the Frame's iris
hardware encoder: RGB24→NV12 box downscale with NEON, H.264 CBR, one frame per slot of an even fraction of the
panel rate read from DRM, e.g. 96 Hz → 32 fps; stdin `k` = keyframe, EOF = stop; `--probe` / `--selftest`;
artifact `linux-arm64-bin/`, synced to `~/.local/share/frameport/bin` by sha256 at stream start, no agent change)
piped into ffmpeg (`-c:v copy` + AAC), else the old ffmpeg/x264 30 fps path (qualities scale down only; "full" =
SteamVR's size; stderr `live: encoder=… fps=…` → status line) →
fragmented MP4 on an SSH exec channel's stdout (stdin EOF stops it) → relay on 127.0.0.1 (a new viewer asks
the hardware encoder for a keyframe and waits for it, else gets init + fragments since the last keyframe of the
*video* track) → player page
`install/live_player.py` (MSE; starts muted as browsers require, "Sound on" button; 0.3 s cushion, catches up at
1.1x, seeks only when >2 s behind: seeking to the very edge starved it) opened
in the user's default browser: Flet can't show video outside `flet build` bundles; the stream outlives the tab and
stops on disconnect/window close); monitor (`views/monitor.py` + `frame/monitor.py` + agent v62 `_monitor`: one
JSON sample per tick over an SSH exec channel while the tab is shown (stopped in go/disconnect/on_close, the
agent ends at EOF); sources and costs in docs/FRAME_RUNTIME.md "Monitoring sources"; game card (fps from
FrameBridge pacing; End game = Steam's Exit game, then cmd_stop), tiles with `C.Sparkline` (Flet canvas, no charts
extension), details, a pooled process table (Game / Steam & SteamVR / All; right-click: end / force kill / end
game; MON_CRITICAL needs force, MON_NEVER is refused)); settings; welcome; activity panel). Files, Screenshots and the Library share right-click menus
(one `ft.ContextMenu` per view, filled on right-click; on one of several selected items they act on the whole
selection, `C.menu_targets`) and click-and-drag multi-select (`C.DragSelect`: pan start/end on the area + item
hover events, which Flutter also sends with the button held; Flet can't report item positions, so no rubber band).
Selection bars sit below the list: above it, their appearing shifted the items mid-drag. Async handlers (they
await a FilePicker) must be coroutine functions or go through `page.run_task`: Flet doesn't await a lambda's
coroutine (the Files row Download button silently did nothing). `ui_smoke.py --fake-frame --gestures` drives real
mouse drags/right-clicks.
User tags live in library entries (`tags`), filters in library setting `ui.library`.
**Performance rules** (the app froze before): never put image bytes in controls — artwork is served by URL from the
GUI assets dir (= user data dir; `ft.run(assets_dir=…)`), as thumbnails (`artwork/thumbs.py`, Pillow); the
@@ -22,6 +60,7 @@ Read `docs/PLAYBOOK.md` (symptom → fix) before debugging a game, and `docs/FRA
job/connection events call `app.refresh_view()` (targeted), not `render()`; no I/O in render paths.
**Never recreate clickable controls on progress ticks** (sidebar, activity tiles): update their properties —
replacing them 5×/s swallowed clicks (couldn't leave the Library during an upload).
Labelled switches: `C.switch(label, …)` (Material's default label colour is dark on our dark theme).
Help hints: wording for non-obvious terms lives in `ui/help.py` (`HELP`); show it with `C.help_icon(key)` or the
`help=` argument of `section`/`status_row`/`kv`, tooltips via `C.tip()` (wraps). Game actions for the Library
right-click menu (one `ft.ContextMenu` around the grid, filled on right-click) and the game page's "…" menu come
@@ -32,18 +71,31 @@ Read `docs/PLAYBOOK.md` (symptom → fix) before debugging a game, and `docs/FRA
uploads are interruptible (Cancel checked per MiB) and resumable (big files via SFTP `.part` append, small files
streamed in tar batches; the agent counts files already in `incoming/`). Multi-select in the Library queues
installs after asking every needed question up front. Failures end in one pop-up (Resume / Uninstall / log).
- Other drives (GitHub #90, agent v63): anchors stay in ~/Applications/quest-frame, a game's files may live in
`<mount>/FramePort/<pkg>` (`deployment.json` base). Agent `drives` (/proc/mounts, /run/media + Steam library
drives; vfat/exfat/ntfs/read-only refused), prepare*/finalize_linux `dest` (unmounted = error, never a fallback;
installed games keep their base), `move` (detached systemd-run + `move_status`; cp -a under podman unshare,
count+bytes check, symlink retarget, launch.sh: Quest app_dir line / Linux+PC VR rewritten from the record's
`launcher` field, else text swap), list_installed `drive`/`drive_missing` (install_state keeps such games
"installed"). PC: `install/drives.py`, library setting `install.drive` (Frame page → Storage), game menu
"Move to…" (job kind tool-frame), CLI `frame drives`/`frame move`/`install --dest`. Untested on the device.
- **PC VR repacks are pre-patched to run directly** (proven: Rick and Morty, Vader Immortal run when the exe is
launched directly; Revive breaks them). So Rift games default to `as_is` = install the copy unchanged and launch
the exe directly (`pcvr.xr_timefix` for the Frame OpenXR-1.1→1.0 fix, `pcvr.no_crash_reporter` for Unreal).
**Revive is off by default, opt-in** (`pcvr.revive`, and `pcvr.oculus_unreal`): only for an un-cracked Oculus game
that fails at "Initializing OVR session". Those (Lone Echo, Robo Recall, Lies Beneath: crack .7z not extracted /
**Revive is only suggested for games with Oculus (LibOVR) code** (`pcvr.revive`, and `pcvr.oculus_unreal`; repacks
with a bundled Revive and SteamVR/OpenXR games run directly): needed by an un-cracked Oculus game that fails at
"Initializing OVR session". Those (Lone Echo, Robo Recall, Lies Beneath: crack .7z not extracted /
Platform SDK) hit Revive's Oculus-runtime **signature check** under Proton-arm64 — Revive's LoadLibrary/WinVerifyTrust
hooks don't install (ARM64EC), and the game's Oculus SDK shim rejects the unsigned Revive runtime (wintrust +
crypt32 signer "Oculus VR") — so they don't run on the Frame without extracting the repack's crack (which FramePort
doesn't do). `VD.bat` is Virtual Desktop's launcher: ignore it except as an exe-location hint. Library migration
`rift_run_direct` resets existing recipes.
Auto launch-test is skipped on PC installs (it would start the game on the user's desktop). Launch tests collect the Unreal
game log + crash summaries from the Proton prefix; triage `unreal-crash`. Lies Beneath via Proton without Revive
game log + crash summaries from the Proton prefix; triage `unreal-crash`. Agent v67 adds Unity's logs (LocalLow/<Company>/<Product>/Player(-prev).log via `<Name>_Data/app.info`,
`output_log.txt`, Temp/…/Crashes/*/error.log; `unity_logs`) to launch tests and diagnostics; triage `unity-vr-init` /
`unity-crash`. A catalog recipe verified with another build (catalog `xr` ≠ the build's) keeps the build's own
`pcvr.launch_args` (`engine._other_build`; GitHub #105: SUPERHOT VR's Oculus+OpenVR build needs `-vrmode OpenVR`,
the catalog's is the OpenXR build); Electron launchers next to a game rank −30 (`rift.is_electron`). Lies Beneath via Proton without Revive
crashed (UE 4.23 "Unhandled exception").
- Rift scanning: `sources/rift_dump.scan` = the scanned folder's subfolders are games (one per folder; a folder is a
game if all candidate exes sit under one child), recursing into collections; `analysis/rift.py` walks once,
@@ -67,15 +119,35 @@ Rick and Morty runs on the Frame via its catalog recipe (OpenVR, no Revive),
auto-start SteamVR on Play (`winhost.start_steamvr`); the Frame launcher always uses `/openxr`. UI (`game.py`
where()) states per-game where it runs; installing an Oculus game on the Frame shows a warning. Migration
`rift_frame_native` re-analyzes + re-derives existing entries.
- Own artwork (0.8.0): game menu → "Use your own artwork…" (also from the Find artwork dialog) =
`views/art_dialog.show_custom_art_dialog`: one slot per kind (portrait/landscape/hero/logo/icon), FilePicker →
`sources.apply_custom` (Pillow check, ≥64 px, ≤40 MB, scaled to ≤3840 px, PNG if alpha/logo/icon else JPEG,
replaces only that kind + its thumbnails, drops the generated cover/banner, writes `.picked` = "custom") /
`remove_custom`; Steam shapes are still composed from what exists (`steam.py` PREFER).
- Art for Rift games: `artwork/sources.py` — Quest version package (OculusDB packageName, exact name or +
"Unplugged"-type suffix, never sequels) → Meta art; OculusDB square cover; Steam (exact names only); exe icon.
- Store details (`artwork/details.py`, entry `details`): OculusDB (description, genres, publisher, website; by Quest
package or Rift match) + Steam appdetails (exact title: developer, release date, up to 6 screenshots → artwork
`shot_N.jpg`). Meta store pages reject scraping, so Oculus exclusives have no screenshots. Genres become automatic
tags. Steam shortcuts get a complete composed art set (`artwork/steam.py`: 600×900 / 920×430 / 1920×620 / logo /
256 icon, blurred-backdrop compositing for square-only covers) and tags: how it runs, the original platform
256 icon, blurred-backdrop compositing for square-only covers; no store art (at most the APK icon) → a placeholder
set: the name on a colour from the title hash + the APK icon, `steam_set_for`; 2D Android apps get no store lookups) and tags: how it runs, the original platform
(Meta Quest / Oculus Rift), genres, user tags — merged with tags set in Steam (non-Steam shortcuts can't hold a
description).
- Linux apps (GitHub #31, library kind `linux`, `linux.<slug>`; x86_64 builds run through FEX (app 3127680, no SLR:
RootFS /usr/share/guestos/fex-mesa from the OS image; needs `STEAM_COMPAT_DATA_PATH`, see docs/FRAME_RUNTIME.md):
agent v61 `linux_x86_tools`/`pick_tool`, `install_proton`/`proton_status` `kind: linux_x86`, `finalize_linux
x86_64`, `installer.ensure_proton(kind=)`; an arm64 program wins over an x86_64 one): GUI = Add
games → "Add a Linux app…" /
"…folder…" (`app.add_linux` job → `pipeline.add_linux_app`); game page `linux_summary` (program + Change…, AppImage,
OpenXR, source) instead of recipe/patches, `C.missing_libraries` callout (Frame deployment, else last install);
no Analyze/Rebuild/recipe/share/Game settings actions, Frame only; platform "Linux" badge + library filter; Steam
tags "Linux app on Frame"/"Linux"; `_follow_catalog` skips them; local files of a lone AppImage = the file only.
Desktop Mode entries (GitHub #84, agent v63): finalize_linux writes `frameport-<slug>.desktop` to
~/.local/share/applications (+ ~/Desktop if it exists; `X-FramePort-Package` marks ours), launch.sh with
`FRAMEPORT_DESKTOP=1` skips the Steam-parent watchdog and Steam's display; ensure_host_fixes refreshes entries
(older installs, stale ones removed), uninstall/purge remove them. Per app: library entry field `desktop_entry`
(default on; patches don't apply to Linux apps) → game page switch → agent `desktop_entry`. Untested on device.
- Quest/Rift twins stay separate entries, shown and named in Steam "Title (Quest)"/"(Rift)" (`core/titles.py`).
- `Recipe.as_is` = install unchanged (pre-patched libraries): `pipeline.prepare_as_is`; auto for APKs that already
contain FrameBridge (`frame_patched`). For Rift it changes nothing (the dump is never modified; the Frame copy
@@ -91,11 +163,17 @@ Rick and Morty runs on the Frame via its catalog recipe (OpenVR, no Revive),
- `patches/` — **the unit of modularity**. `base.py` (Patch interface, registry), `overport.py` (overport CLI patch ids,
discovered dynamically via `overport patches`), `frame/*.py` (one module per Frame fix), `settings.py` (FrameBridge
adapter keys + device files as patches). Add a patch = add a module that calls `register(...)`.
`upstream.py`: upstream fixes that replace a workaround per build (a probe finds the fix in OVRPort's output →
the build leaves the workaround out, `build.superseded`; recipes unchanged). Registered: `ovrport.haptic_envelope`
(→ `adapter.haptic_fix`, `frame/haptic_envelope.py`) and `ovrport.microphone_stream` (→ `frame.ovr_microphone`),
both fixed in OVRPort runtime 3.4.3-aa54c3f (ovrport/app#73; haptics owner-verified with Lucky's Tale 2026-10-07).
- `analysis/` — APK/ELF inspection (`detect.py`), `elf.py` (pyelftools reads; own DT_NEEDED writer), `stubgen.py`
(generates the ovr_* stub .so without a compiler).
- `apk/` — `axml.py` (binary manifest editor), `workspace.py` (staged zip edits), `sign.py` (apksigner; it aligns too).
- `recommend/` — `catalog.py` (known-good recipes: user > remote `FRAMEPORT_CATALOG_URL` > bundled), `engine.py`.
- `tools/` — portable toolchain (Temurin JRE, overport jar, apksigner) downloaded dynamically into the user data dir.
The overport CLI comes from the downstream fork **Android-XR-Bridge/OVRPort** (stable `vX.Y.Z` releases,
`OVRPort-<ver>-stable-cli.jar`; fallback ovrport/app `cli-jar.zip`), see "overport" below.
- `frame/` — SSH (paramiko), mDNS discovery, pairing server; `install/installer.py`; `validate/` (static, device, triage).
- `targets/` — `Target` interface; `frame_lepton.py` (Quest via Lepton + Rift via Proton), `pc_revive.py` (Rift games
on this Windows/WSL PC via Revive + local Steam shortcut; `core/winhost.py` = Windows/WSL helpers).
@@ -129,11 +207,14 @@ Rick and Morty runs on the Frame via its catalog recipe (OpenVR, no Revive),
[--yes]`, once-a-day stderr hint read from the cache only (`refresh_cache()` in a daemon thread writes no
settings, to avoid read-modify-write races). `scripts/update_smoke.py <archive>` runs the real extract + swap script
(no relaunch) — CI runs it on all three OS with the archive it just built.
Verified: Linux + Windows (native, signer check) smoke with the v0.2.0 bundles; macOS only via the CI smoke.
Verified end to end (2026-10-02): real 0.3.3 bundles on Windows and Linux (Ubuntu 22.04/WSLg) found, staged and
installed 0.3.4 ("Install updates automatically" path) and relaunched as 0.3.4 with settings kept. Not yet clicked
by hand: the "Update now" button path (same apply(), called from the running app). macOS: CI smoke only.
- `agent/frameport_agent.py` — runs **on the Frame** (python3 stdlib only), JSON over SSH. Owns the install layout,
launch.sh template, Steam shortcuts (binary VDF), launch tests. Bump `AGENT_VERSION` when changing it.
- `bootstrap/bootstrap.sh` — one-time Frame setup served by the pairing server (sshd, app key, avahi service, Lepton).
- `catalog/games/<package>.yaml` — 34 recipes verified 2026-09-28 + Deadpool VR (2026-10-01, owner-confirmed); `catalog/triage.yaml` — log signatures → fixes.
- `catalog/games/<package>.yaml` (installed apps also fetch these from GitHub `main`, see "Catalog updates") — 38 recipes (34 verified 2026-09-28; Deadpool VR, 4XVR, NEX Player and AC Nexus's
90 Hz default confirmed later by the owner); `catalog/triage.yaml` — log signatures → fixes.
- `native/` — sources of the prebuilt binaries in `artifacts/` (adapter, VrApi bridge patches, GL shim, stubs).
`native/build.py` rebuilds them with NDK r27c (downloaded on demand into `native/.cache`, git-ignored; uses
`-ffile-prefix-map` so no local paths get embedded; zip symlinks are restored as copies). Users never need the NDK.
@@ -146,9 +227,9 @@ Rick and Morty runs on the Frame via its catalog recipe (OpenVR, no Revive),
UV_LINK_MODE=copy uv sync --extra dev # creates/updates ./.venv
uv run pytest # unit tests (no device, no game files)
uv run frameport --help # CLI; uv run frameport-gui for the GUI
uv run frameport parity --known-good <PATCHED/_known-good-*> --sources "<VR CyberDeck downloads>"
uv run frameport parity --known-good <PATCHED/_known-good-*> --sources "<folder with the game dumps>"
```
Games/device tests: `pytest -m games` (FRAMEPORT_GAMES=<downloads dir>), `pytest -m device` (FRAMEPORT_FRAME=steamos@host);
Games tests: `pytest -m games` (FRAMEPORT_GAMES=<downloads dir>); on-device checks are CLI commands (below);
native layer test: `FRAMEPORT_NATIVE_TESTS=1 pytest -m native` (compiles with the NDK, ~2 min on NTFS).
Repo is on an NTFS drive (`core.fileMode=false`); line endings are LF (`.gitattributes`).
- `FRAMEPORT_HOME=<dir>` isolates all app data (tests use it); `FRAMEPORT_JAVA/_OVERPORT_JAR/_APKSIGNER_JAR` override
@@ -156,6 +237,13 @@ Repo is on an NTFS drive (`core.fileMode=false`); line endings are LF (`.gitattr
artwork, frames.json, the app's SSH key which the dev Frame authorizes).
- Device checks: `frameport test <pkg>` / `frameport parity-device --results <parity.json> --baseline <launch.txt>
[--test-only]`; the pre-FramePort baseline is `PATCHED/_known-good-2026-09-28/_frame-state/baseline-launch.txt`.
- Docs screenshots (`docs/images/`): `python scripts/scrub_library.py ~/.local/share/frameport <dir> --status works,issues` (copies
library + artwork only; titles replace folder names, local paths → `D:/Games/...`, sort by size) then
`FRAMEPORT_HOME=<dir> python scripts/ui_smoke.py --out <shots> --docs --fake-frame --game <pkg>` (set
FRAMEPORT_JAVA/_OVERPORT_JAR/_APKSIGNER_JAR so no tool download toast appears; `--viewport 1280x2600` + crop for the
patch list). Check every PNG for paths, IPs, user names and repack/scene names before committing.
README rules (owner): states the project is a proof of concept, provides no piracy tools, credits the wrapped
projects (most functionality is theirs); neutral technical wording; no Quest2Frame mentions anywhere.
- GUI smoke test: `uv pip install flet-web playwright && playwright install chromium`, then
`FRAMEPORT_HOME=<test dir> python scripts/ui_smoke.py --out <dir> [--game <pkg>] [--frame steamos@<host>] [--update]` (`--update` = fake release: banner, dialog, Settings → Updates) and look
at the PNGs. Flet 1.0 notes: `ft.run` must own the main thread; background work via `page.run_thread`; FilePicker is
@@ -168,6 +256,25 @@ Repo is on an NTFS drive (`core.fileMode=false`); line endings are LF (`.gitattr
an `expand` child in a `wrap=True` Row).
- Stopping the GUI: `pkill -f` patterns match your own shell — use `pgrep -f "[b]in/frameport-gui|[f]let-desktop-light"`.
## Round-2 polish (2026-10-02)
- `errors.py`: `explain(exc)` (plain sentence for GUI + CLI), `is_connection_error`. Install/test jobs for the Frame
(`Job.needs_frame`) that lose the connection go back to the queue front and the queue pauses (`jobs.paused`);
`app._poll` retries every 10 s and resumes (owner-verified on the device 2026-10-02: the queue resumed after the
connection was lost). Wake lock: agent v30 `keep_awake` (systemd-inhibit idle:sleep, idle-only
fallback because polkit `inhibit-block-sleep` is auth_admin for non-local sessions), held while Frame jobs exist.
- **Already converted inputs** (`analysis.is_overport_output`, e.g. the owner's library points at `PATCHED/` copies)
are not converted again: a second OVRPort run replaced libovrplatformloader.so and dropped its DT_NEEDED on
libovrstubs.so (Wallace & Gromit / Espire 2 crashed: cannot locate symbol ovr_…). Alt builds come from the saved
`<pkg>.alt-noforcequit.apk`, else one OVRPort run (frame.ovrstubs relinks). `missing_ovr_symbols` only counts
linked stub/compat libs. Converted copies in `output/` are removed after a Frame install (`build.keep_copies`).
- Art: `.picked` marker = user's pick, automatic fetches never overwrite it and only fill missing kinds; a Meta
result's picture is the OculusDB image shown in the picker (the ovrp image service served "dogfooding" placeholder
covers for some packages, e.g. Asgard's Wrath 2). `steam_art_stale` → game page reminder. No store art → generated
`cover.jpg`/`banner.jpg` (APK icon via `fetch.apk_icon`).
- Game settings dialog (`ui/views/adapter_dialog.py`, metadata `patches/settings.UI`); plain patch summaries
(`patches/summaries.py`, `Patch.summary`, "Show technical details" = setting `ui.patch_details`); share nudge
(`views/game.should_ask_to_share`); saving a recipe keeps its status (was always "works").
## Hard-won facts (don't re-learn these)
**Frame runtime (SteamOS 0.3.0, build 20260922):**
- No AArch32: 32-bit-only APKs fail with `INSTALL_FAILED_NO_MATCHING_ABIS`. Unfixable; point to Rift + Revive.
@@ -184,7 +291,28 @@ Repo is on an NTFS drive (`core.fileMode=false`); line endings are LF (`.gitattr
- **Tracking only works with the headset worn.** SSH/headless launches never reach VISIBLE/FOCUSED and poses have
flags 0x3. So automated tests prove startup (process alive, instance/session created, frames paced), never visuals.
**Setup / pairing (2026-10-02, verified on the device):** Developer Mode = `"DevModeEnabled"` in
`~/.local/share/Steam/config/config.vdf` (InstallConfigStore/developer), applied by Valve's
`/usr/bin/steamos-polkit-helpers/steamos-devkit-mode --enable|--disable` (polkit allow_any: no password; enables/
disables sshd, xrdp, steamos-devkit-service, debug port forwards; sentinel `/etc/steamos-devkit-enabled`). Steam
re-asserts the config value at every start and rewrites config.vdf on exit → stop Steam, edit, helper, start.
**Desktop Mode is a nested Plasma inside steam.service** (own XDG_RUNTIME_DIR `/run/user/1000/nested_plasma` + private
D-Bus): `systemd-run --user` from Konsole fails ("Failed to connect to user scope bus") unless XDG_RUNTIME_DIR/
DBUS_SESSION_BUS_ADDRESS point at `/run/user/$UID`, and stopping Steam ends the desktop and everything started in
it → bootstrap.sh runs the Dev Mode job + Lepton request + `/paired` as a user unit (log `~/.cache/frameport-setup.log`);
no sudo/password anywhere (verified: naive Frame → connected, password never set). Valve's devkit pairing (fallback,
PC → Frame only): `POST :32000/register` with an **ssh-rsa** key (`connection.devkit_key`, `frame/devkit.py`) works only
while Steam is in pairing mode (Settings → Developer → Pair new host), else 403 at once; approve hook waits 30 s.
The Frame runs firewalld (22 and 32000 open). PC side: the setup server needs inbound TCP 8765–8767 — WSL's Hyper-V
firewall blocks it silently (`DefaultInboundAction Block`): `pairing.ensure_reachable` adds a temporary rule via one
UAC prompt, removed when the server stops (flag file in %TEMP%, max 35 min); hints per OS after 45 s without a request
(`pairing.firewall_hint`). Flet 1.0 patches aren't thread-safe → `app.serialize_flet_updates()` (a dialog shown while a
scan redraw ran never closed: "dropped a patch for unknown control").
**Lepton:** needs an activity with category **LAUNCHER** (Quest apps often only have INFO → "APP_ACTIVITY is empty").
**2D apps:** Lepton runs every app headless (`lepton.headless=true`, only OpenXR output reaches the headset) unless the app folder (`<base>/lepton-app/`) has a `lepton-show-flatscreen` file (liblepton/app_metadata.sh) → Waydroid window on gamescope; agent v28 `set_flatscreen` at finalize for `vr_kind == "none"`. Android 11's navbar covered the
app's controls → patch `device.hide_navbar` (default on for vr_kind none, migration `flat_hide_navbar`) exports
`qemu.hw.mainkeys=1` as a second line of `LEPTON_GFXRECON_FP_PROPS` (runtime alternatives failed, see
docs/FRAME_RUNTIME.md). Verified in the headset 2026-10-02 (2048).
Lepton = Steam app 3029110 (+ "Lepton Development" 3056000, needs Developer Mode). Per-game env: STEAM_COMPAT_INSTALL_PATH
/DATA_PATH/SHADER_PATH, SteamAppId. Logs: `<base>/launch.log` and `~/.local/share/Steam/logs/lepton-logcats/steamlaunch-<appid>`.
Containers are podman `lepton-steamlaunch-<appid>`. Some Unreal games create save dirs without u+rwx → launcher repairs every 2 s.
@@ -256,6 +384,22 @@ stopping Steam kills them → always run that work via `systemd-run --user` (the
**overport:** always `--version=latest`; `--workspace` holds runtimes and **per-package keystores (password
"password", alias "key") — never lose them**: updates must be signed with the same key or saves are lost on reinstall.
Output is deterministic (same input + runtime → same bytes), which is what makes parity testing possible.
**OVRPort 1.2.5 (2026-10-01, the fork's first release; CLI-only):** same commands (`patches [--json]`, `patch`, `help`,
`install`), but `patch` rejects unknown/duplicate args, unknown patch ids and an empty `--patches=`
(`tools/overport.patch` refuses empty lists). After patching it adds `libovrplatformcompat.so` itself when the platform
loader lacks `ovrMessageType_ToString` (our `frame.ovrplatformcompat` then skips: same library). New patches (all off;
`patches/overport.py`): `patch_ac_nexus_no_appsw_72/_90` (AC Nexus build 207706 only, exclusive),
`patch_disable_meta_xr_audio_telemetry` (x86_64 emulators: hidden), `patch_vrapi_openxr` = OVRPort's VrApi adapter =
the **unpatched** upstream of our `frame.vrapi_bridge` (`native/vrapi` unchanged since our 5e7df52), only usable with an
experimental CLI built with `-PwithVrApi=true` (stable jars list it but fail). The owner prefers OVRPort's fixes over
ours where they work as well (less to maintain): compare in the headset before switching a default.
`frameport install <pkg> --apk <file>` installs a specific (test) build signed with the game's key.
Headset results (2026-10-02, `PATCHED/_test-ovrport-1.2.5/TESTING.md`): OVRPort's own VrApi translator fails on the
Frame (Climb 2: requests VkFormat 37 → crash; POTW: no GLES path, missing `vrapi_GetTextureSwapChainHandle`) → keep
`frame.vrapi_bridge`; those two changes are upstream candidates. 1.2.5 builds (its platform compat, new permissions)
work. AC Nexus: `patch_ac_nexus_no_appsw_90` is the catalog default (owner preferred 90 Hz); `STRICT` patches are only
taken from a catalog recipe where `applies()` holds (the AC Nexus ones need build MAIN.450412.207706.final, else the
whole overport run fails).
**Patching gotchas:**
- UnityPy re-serialization breaks scene loading → patch QualitySettings ints in place.
@@ -305,7 +449,7 @@ GPU. Learned in the headset: quads can't be a background (the Frame draws quad l
whatever the order: hid 4XVR's balcony/controllers), and the Frame doesn't reproject a projection layer from its own
pose (images drawn only after head turns, or ahead from xrWaitFrame and sometimes late, wobbled);
`equirect_flip/face/res/fps/stereo`), `stable_local`, `focus_hold` (only after 3 s FOCUSED, dips <600 ms),
`aim_pitch/aim_yaw/aim_forward`, `refresh_rate`, `layer_debug` (diagnostics). 4XVR re-creates LOCAL spaces every 2–4 s
`aim_pitch/aim_yaw/aim_forward`, `refresh_rate`, `layer_debug` (diagnostics); focus_hold is default-on since 2026-10-05. 4XVR re-creates LOCAL spaces every 2–4 s
(menu recentring suspect); its theatres are baked 7680×3840 equirect2 images (`assets/100.png` …). Test 360° videos
(NASA, public domain) are in the Frame's ~/Videos; copies in `~/Downloads/frameport-360`. 4XVR's "Internal Storage"
lists its own `/sdcard/4XPlayer`, not Movies: agent v25 `link_media` hard-links sent files into an app's own top-level
@@ -315,19 +459,300 @@ swapchain was halved (1536/eye) in case memory is the limit (unverified). Frame
(SteamVR runtimes, Lepton scripts, logs; never commit Valve binaries): `~/frameport-research/frame-data-2026-09-30/`.
Not yet verified in the headset.
**Lepton storage (2026-09-30):** each app's /sdcard (= /storage/emulated/0 → `<base>/lepton-data/external`) has `Movies`/`Download`/`Documents` symlinked to the Frame's `~/Videos`/`~/Downloads`/`~/Documents` (liblepton/mounting.sh, only if they exist at start); agent v24 `storage_targets` reads that mapping. Android's MediaProvider canonicalises paths to /home/steamos/... and rejects every file ("doesn't appear under [/system/media...]"), `sm list-volumes` is empty: the media index never works, apps must browse folders. Lepton installs with `adb install -g` (runtime permissions granted, MANAGE_EXTERNAL_STORAGE too). Send files: `install/files.py`, `frameport frame send|storage`, GUI Frame → Send files.
**Companion apps / intents (2026-10-03, tested with Stremio + 4XVR):** a second APK can be installed into a running
Lepton container (`podman exec -i lepton-steamlaunch-<appid> pm install -g -S <size> < apk`) and runs there, VR
included (4XVR in Stremio's flatscreen container: FrameBridge 72 fps, settings via LEPTON_ENV_FRAMEBRIDGE_CONFIG). But
Lepton's services.jar (`ActivityStarter.execute`) intercepts **every** `android.intent.action.VIEW` with data (any
scheme, explicit component or not, no property to disable): it writes `steam://openurl/<uri>` to `/lepton/steam.pipe`
(= the host Steam client's `~/.steam/steam.pipe`) and starts nothing. So "open in external player" hand-offs (Stremio
→ 4XVR) can't work inside Lepton; don't retry without Valve changing it. Lepton installs exactly one `*.apk` per app
folder (two break `get_apk_path`).
**Text input (2026-10-03, verified in the headset with Stremio VR):** Lepton's Android has no IME (`ime list` empty)
and runs VR apps headless (`lepton.headless=true`): no Android window has input focus (`dumpsys input` FocusedWindows
empty), so neither `input text`, a USB keyboard nor Steam's keyboard reach the app. `lepton-show-flatscreen` on a VR
app keeps VR working (FrameBridge 72 fps) and gives the window focus; Steam's on-screen keyboard then opens for text
fields. Unity's TMP_InputField on non-Quest Android waits for the system keyboard (`TouchScreenKeyboardShouldBeUsed`)
and deselects a frame later unless `isKeyboardUsingEvents` (Android: `InPlaceEditing() && m_HideSoftKeyboard`);
uGUI InputField's LateUpdate keeps the field when `InPlaceEditing()`. Patch `frame.unity_text_input` rewrites them
(`mov w0,#0|#1; ret`) at Cpp2IL's **Offset** (= file offset; RVA differs by 0x4000 in Stremio's lib), Cpp2IL
2022.1 pre-release (Unity 6 / metadata v31; Il2CppDumper can't), cached per libil2cpp sha. `/dev/uinput` has an ACL
for steamos (Steam Input) → agent v33 `_keyboard` uinput keyboard ("Type on Frame") reaches everything with focus.
Installing a second APK into a container with `pm install` re-runs Lepton's post-install hook on the **main** app
(`lepton.active_app_id`; moves its files to /data/steam_app) and corrupts it on the next start (fix: touch the APK →
re-bake); `cmd_real package install` skips the hook.
**User reports (2026-10-04, issues #4-#10):** Steam shortcuts go to the signed-in account (`loginusers.vdf`
MostRecent) else every account (agent v35 `library_users`; it used to refuse with >1 account → Play gave Steam's "Game
configuration unavailable"); `launch` uses the shortcut's own appid and errors `NOT_IN_LIBRARY`, the app then adds it
and plays. Unity IL2CPP fixes share one Cpp2IL run (`unity_text_input.Il2cppReturnPatch`, `ALL_TARGETS`, cache keyed by
global-metadata.dat): `frame.unity_runtime_msaa_off` (OVRManager raises MSAA to 4x at runtime: "Switching to the
recommended level" → Lucky's Tale restarted the headset; `OVRDisplay.get_recommendedMSAALevel` → 0) and
`frame.unity_multipass` (Oculus XR Plugin multiview → MultiPass via `OculusSettings.GetStereoRenderingMode`; I Am Cat's
right eye grey). Both checked against Toy Master's Cpp2IL output, not yet in a headset. VR4 quits itself (System.exit
after the intro movie) → catalog `use_alt`. **Catalog changes reach existing games** without hardcoded migrations:
recipes store `catalog_rev` (= `CatalogEntry.rev()`), `library._follow_catalog` re-derives non-user recipes whose entry
changed; a maintained entry beats the user's shared copy when its `updated`/verified date is later (`catalog._newer`).
**Round 2 of reports (2026-10-04):** VR4's campaign hang = one fragment shader reading an uninitialized loop counter
(reporter's capture): vkshim `vk_shader_fix` setting (`<size>:<sha256>:<offset>:<words>`, from the recipe's `adapter:`;
matched by size + SHA-256, words inserted into a copy) — on the device the module is fixed at load ("fixed shader
module (6488 -> 6512 bytes)"); campaign itself not yet seen in a headset by us. Text settings (kind "str") stay out of
the Game settings dialog (saving it dropped them). I Am Cat: `GetStereoRenderingMode` is inlined (no call sites) →
`Il2cppReturnPatch.field_loads` rewrites the field read in `OculusLoader.Initialize` (Cpp2IL gives the field offset,
`field:<name>`); verified with Toy Master: eye swapchains array=1 ×2 instead of array=2. Builds record `recipe_fp`
(`patches/base.recipe_fingerprint`, `Patch.revision`): a changed recipe or revised patch shows "Update on Frame".
Remembered Frames are found again after an address change (`Frame.relocate`: scan, same SSH host key, before
login). Packaged apps show artwork by file path (`thumbs.use_file_paths`, #16). Diagnostics: this boot's kernel log.
Device tests of requested games (2026-10-04, headless): I Am Cat, Myst 3.3.0, BattleGlide, Blade & Sorcery: Nomad
start (RUNNING, frames). Roblox: SIGSEGV in je_free from libroblox.so ~3 s in (likely its anti-tamper vs the re-signed
APK). BONELAB (Unity 2021.3 Vulkan, OVRPlugin 1.94): SIGSEGV with pc == fault addr in vkCreateInstance, called from
libSLZQuestNative.so's Vulkan hooks into an unmapped (unloaded) library right after OVRPlugin's pre-init
xrDestroyInstance; pinning openxr/vrclient libraries (RTLD_NODELETE) did NOT help — find the unloaded library with the
linker's dlopen/dlclose logging next. Accounting+ (Unity 2017.4 built-in Oculus, libOVRPlugin + libvrapi): Unity
never starts VR on the Frame (no OVRPlugin/OpenXR lines; runs as a 2D app), which is why its "controller setup"
screen can't be passed — Unity 2017's Oculus device check, not the controller profiles. Cpp2IL can't read Unity 2017.
The Frame's Android runtime (vrclient.so) knows oculus/touch_controller but not Meta's Touch Plus/Pro profiles
(OVRPlugin suggests those too, routinely) → adapter `profile_remap`.
Headset round 2 (2026-10-04): the Frame drops focus often (ms to 7 s; only some are presence/standby) → games pause
or recentre (B&S Player.OnVRPresence → Teleport, BattleGlide/Unreal pauses); focus_hold now 1 s focused / 1 s max dip
(longer must still pause). Myst crash = vrclient xrSyncActions race after FOCUSED → `sync_guard` (confirmed); its
object glitches: app space warp suspected (FB_space_warp is advertised and used) → recipe `patch_disable_space_warp`.
I Am Cat multipass: poses/times consistent, but every frame is submitted after the next xrWaitFrame (one period late;
Zink + doubled draws) and the game clamps its physics step to 10 ms → judder while still; testing scale 0.8. Roblox's
newest crash is on Fossilize's recording thread → vk_sanitize extended to own-engine libs (engine "Other").
Accounting+: unity_oculus_check + native/ovrpshim (libfp_ovrp.so waits via ovrp_WaitToBeginFrame before Unity
2017's ovrp_Update2) → VR in the headset at ~72 fps (2026-10-04), but stuck at "press any button" although input
reaches its OVRInput cleanly (probe: both Touch connected 0x63, individual buttons, input focus 1) → works with issues.
"outside of frame bounds" warnings stay (~2/frame) and are harmless.
Steam library (GitHub #4/#21/#27, agent v38): shortcuts go to every Steam account (signed-in first; MostRecent isn't
always the account on the Frame); stop_steam also waits for Steam's helpers; after the restart the agent re-reads
shortcuts.vdf and writes once more if Steam put its old copy back (`shortcuts_lost`), else reports it. 0.6.3's Play
auto-repair (`_add_then_play`) crashed (its job got a Job, not a reporter). Uploads resume on a transient OSError.
Lepton's Android 11 has no clipboard service (134 services; checked with `podman exec … service check clipboard`):
SDL/LÖVE apps crashed at start → `frame.sdl_clipboard` (`apk/dex.py`: in-place dex edit, nops one invoke, fixes
the header checksum/signature; verified with LÖVE for Android 11.5, GitHub #24 Dramatic Shape). 2D apps (vr_kind none)
keep every suggested patch that isn't about VR (`needs_vr = False`), not a fixed list. FramePort on the Frame:
`frame/local.py` (127.0.0.1, own key authorized; "This Frame (experimental)"; app data in
~/.local/share/frameport-app because ~/.local/share/frameport is the agent's) and Steam library changes wait while
Desktop Mode is open. Verified on the device 2026-10-04 (install + launch test from the Frame). Library updates on the
Frame run one at a time (agent v40 flock): two quick uninstalls used to bring a removed shortcut back (Roblox).
Headset round 3 (owner's verdicts, 2026-10-04): Blade & Sorcery works — its freezes were the headset's wear sensor
flickering off while worn (vrserver.txt "HMD off/on" 0.5-2 s) → per-game `focus_hold_ms=2500` (only this game reacts;
not a default). BattleGlide works (focus_hold). Myst works with issues (object glitches; space warp ruled out, its
recipe keeps it on). I Am Cat works with issues (judder; scale 0.8 no help). Roblox unsupported (je_free in
libroblox, also with the Vulkan shim). Installs skip the Steam restart when the shortcut is unchanged and wait while a
game runs (agent v37). New default fixes in FramePort's code reach games already in a library: after every app update
`library._follow_catalog` re-derives each non-user recipe once (setting `recipes.app_version`; tests switch it off via
`library.REFRESH_ON_UPDATE`). Analysis fields added later: **bump `analysis/detect.ANALYSIS_VERSION`** (stored as `analysis.extra.analysis_version`); older entries whose APK is still there are analysed again at the GUI's start (background thread, not a job: ~8 s per 900 MB APK) and before a build (`pipeline.refresh_analyses`, GitHub #104); only `analysis`/`suggested` change, user recipes stay; an unreadable APK gets `analysis_failed` = the version (not retried until the next bump). Troubleshooting techniques: docs/PLAYBOOK.md "Debugging techniques". Unity `boot.config` "vulkan" substring mislabels GLES games as Vulkan
(I Am Cat ran GLES); OVRPlugin's "Unavailable OpenXR extension: XR_FB_scene" is routine (no longer triaged).
**Round 4 (2026-10-04):** XR_KHR_android_surface_swapchain is listed by the Frame's runtime but returns
FUNCTION_UNSUPPORTED → adapter `surface_emul` (default on, `native/adapter/surface_swapchain.c`): an ordinary runtime
swapchain is returned, the game gets a Surface from a SurfaceTexture on a worker thread (own EGL context, JavaVM from
XrInstanceCreateInfoAndroidKHR), frames are read back (glReadPixels) and uploaded in xrEndFrame (Vulkan: own command
buffer + fence per panel, never waits; GLES: glTexSubImage2D). I Am Monkey's intro works (owner-confirmed). SUPERHOT
(Quest) quit at start: its cloud save folder was mode 1700 and Lepton's app writes through the folder's group →
launch.sh `fix_perms` adds u+rwx,g+rwx (agent v41). Lucky's Tale: Unity's Loading.PreloadManager thread grows the
native heap ~1 GB/s until the OOM killer (Frame freezes); no fix. `perf` works as steamos (paranoid 2; ptrace_scope 1
blocks gdb/eu-stack/debuggerd) — see PLAYBOOK "Debugging techniques". QuestCraft downloads its JRE at first run into
`files/runtimes/JRE` (Pojlib Installer); on the Frame it was missing (unpacked by hand, unverified). WiiCompiled: its launcher shows
(lepton-show-flatscreen) but imports .wcgame files through Android's document picker (OPEN_DOCUMENT), which Lepton
lacks (ActivityNotFoundException) → imported by hand: libmain.so + game.json → internal files/game/<profile>,
DATA/ → external files/WiiCompiledOpenXRVR/DATA, MOD/ → .../RetroRewind6 (decompiled with jadx). Lepton has no
picker at all: a FramePort fix would be an injected picker activity. Generated cover/banner art used to suppress the
Steam placeholder set (no Steam art at all) → fixed in artwork/steam.py.
**Steam library failures (GitHub #21/#30):** on some Frames Steam never loads FramePort's shortcuts.vdf entries (same SteamOS build and arm64 beta client as the dev Frame; IDs correct; file written before Steam starts): Play → console_log `GameAction [AppID <id>] … RequestingLicense → UpdatingAppInfo → LaunchApp failed with AppError_9` (= "Game configuration unavailable", Steam treats the id as a store app). Cause unknown; agent v42/43 diagnostics: `launch` returns `steam` (started / error + code / silent from console_log), `collect_diag` adds `steam_library` (real Steam dir, beta, Steam start vs vdf write time, entries per account, devkit games) + `steam-console.txt` (incl. Steam's `logs/shortcuts.previous.txt` if present; steamclient.so has "LoadShortcuts: rejecting attempt to load shortcuts: invalid account ID"). **Fallback (agent v43):** when Play gets AppError_9 the agent registers the game through Steam's devkit interface (what Valve's Devkit Management Tool does, MIT: `devkit-1 steam://devkit-1/<~/.steam/steam.token>/create-shortcut?response=<file>&gameid=<id>&directory=~/devkit-game` written to ~/.steam/steam.pipe; answer file / `.error`; `~/devkit-game/<id>/launch.sh` = link to the game's launch.sh, `<id>-argv.json` ["launch.sh"] (relative to the folder), `<id>-settings.json` {steam_play 0, compat_tool ""}). Steam adds it live (no restart), picks its own appid (read back from shortcuts.vdf by DevkitGameID), shows it as a normal non-Steam game named "Devkit Game: <id>" (OpenVR 0, but VR works: owner-verified 2026-10-04), art copied to grid/<appid>*. Ids: letter first, then letters/digits/_ only (spaces, '-', leading digit → "missing/invalid arguments"). Later Plays use the devkit entry; uninstall (`devkit_unregister`, `delete-shortcut` live) and purge remove it. Verified on the dev Frame: register/launch/unregister; the AppError_9 trigger itself only in unit tests. GitHub #42 (two Steam accounts, neither MostRecent): Steam rewrote the active account's shortcuts.vdf without FramePort's entries right after starting, and added the devkit entry live without saving it, so `devkit_appid` (vdf only) failed ("Steam added the devkit entry but didn't save it"); agent v55 `devkit_appid_from_log` reads Steam's `sanitize shortcut app id "~/devkit-game/<id>/launch.sh": replacing 0 with N` console line. GitHub #41 (one account): same Steam behaviour, and every install restarts Steam, which forgets the never-saved devkit entry. Agent v56: the log fallback reads only the current session's console_log.txt; Play re-registers a devkit entry that gets AppError_9; art updates also write the devkit entry's grid art (`copy_grid_art`). Open: why some Frames' Steam never loads or saves shortcuts.vdf (single account too).
**Exit game (GitHub #36, 2026-10-04):** `Apps.TerminateApp` (what Exit game calls; reachable for tests through Steam's CEF devtools on 127.0.0.1:8080, SharedJSContext, `Runtime.evaluate` — a stdlib websocket client is enough) closed both a normal shortcut and a devkit entry on the dev Frame within 1-3 s. SIGTERM to Steam's `reaper` alone left launch.sh + Lepton (setsid) + the container running (an earlier headset launch ran on for 87 min); SIGTERM to launch.sh cleans up in ~4 s. Agent v44: launch.sh's 2 s loop ends the game when its parent (the reaper) is gone; `upgrade_launchers` (from ensure_host_fixes) adds that to existing launchers in place. Which in-headset exit path fails is still unknown. Screenshots on the Frame: all under SteamVR's appid 250820 (`760/remote/250820/screenshots`, screenshots.vdf has creation time, no game).
**SteamVR dashboard at game start (2026-10-04):** the dashboard (Resume game / controller / VR options) was open whenever a FramePort game started (also over Lepton's 2D launcher). Steam's UI exposes `SteamClient.OpenVR.VROverlay.{IsDashboardVisible,HideDashboard,ShowDashboard}` (CEF devtools, `steam_js` in the agent). Agent v44: launch.sh starts `_dashboard_worker` (waits for FrameBridge's first `pacing:` line in launch.log, then hides a visible dashboard for 25 s, at most 3 times; log `<base>/dashboard.log`; opt out with env FRAMEPORT_KEEP_DASHBOARD=1). Verified on the dev Frame (dashboard shown → 4XVR launched via Steam → hidden ~5 s after the first frames); not yet seen in the headset. **Headset (ITR2, 2026-10-05): too late** — Steam shows its frame menu (`valve.steam.gamepadui.frame.menu`, vrwebhelper_systemui.txt `[PooledPopups] Showing`) ~0.3 s after the game's first submitted frame (FrameBridge `new layer:`), but the first `pacing:` summary comes ~8 s later; the owner had pressed Resume (`[HideDashboard] return_to_game`) before the worker looked. Agent v52: watches from the first `new layer:` line (incremental log reads, 0.5 s polls, 30 s window). Agent v59: watches 120 s and hides up to 10 times (the menu came back after 30 s in the owner's sessions). Agent v53: stops for good once the player opens the dashboard with the controller (`toggle_dashboard_action` in vrwebhelper_systemui.txt since the worker started): v52 closed it 60 ms after each press, and the game, paused for it, stayed paused.
**Space warp / ITR2 (2026-10-04):** Into The Radius 2 (UE5, `libUnreal.so` + OVRPlugin, Vulkan) uses Application SpaceWarp (extra swapchains `376x376 format=97` motion vectors + `format=129` depth); #35 reports flickering textures. OVRPort's `patch_disable_space_warp` has no effect on UE5, and hiding XR_FB_space_warp in FrameBridge's enumerate doesn't reach the game either: **OVRPort's dispatcher offers/enables XR_FB_space_warp itself**. FrameBridge `hide_space_warp` (per game, off) hides it and strips `XrCompositionLayerSpaceWarpInfoFB` (1000171000) from the projection views (log `hide_space_warp: removed space warp info`); the game still renders its MV swapchains. Test build installed on the dev Frame; flicker not yet checked in a headset. Heuristic: UE5 + OVRPlugin shows it as an option (off). `equirect_emul` is suggested for Unreal games whose graphics API isn't detected ("GLES or unknown"); on Vulkan it switches itself off (Myst/Riven/ITR2): harmless, but Unreal Vulkan detection is a known gap.
**PR #34 (merged 2026-10-04, Lucas-Mathieu):** `native/adapter/audio_metadata.h` patches Meta XR Audio Wwise (only build ID e1619e7f…, Batman: Arkham Shadow 1.4.1) so queued audio metadata isn't freed while the current audio frame references it (smoke-bomb crash). Verified headless: installs ("metadata reclamation follows …"), 72 fps; we added a once-per-second scan limit. Outside PRs: review source, rebuild `artifacts/` ourselves, merge locally (contributor's commit kept), push main.
**Heuristics eval (2026-10-04):** `scripts/eval_heuristics.py "<VR CyberDeck Portable>"` → 19/44 recipes exact, 322/352 fields (most diffs: `frame.unity_text_input` suggested where older catalog recipes lack it; the rest are runtime-only findings: use_alt, vk_shader_fix, focus_hold, sync_guard, multipass). `PATCHED/` copies aren't scored (already converted).
**Power (0.9, agent v47):** sidebar bar below the Frame card: Sleep / Restart / Shut down, each confirmed (`app.frame_power`, a running game asks again). logind answers CanSuspend/CanReboot/CanPowerOff = "challenge" for an SSH session but "yes" inside a user unit, so agent `power` runs `systemctl suspend|reboot|poweroff` from a transient `systemd-run --user --on-active=3` timer (the command answers first). Restart verified on the device (back in ~84 s, new boot id).
**Proton default (agent v51, owner's choice 2026-10-05):** the newest **stable** ARM64 Proton is the default for PC VR games (`pick_proton`: asked-for name/alias, else newest installed stable, else any stable). Agent v49-50 defaulted to Experimental; the owner's headset A/B with Rick and Morty (Experimental 69 % reprojected frames, stable felt much smoother) reverted it. The game page's Customize shows `pcvr.proton_tool` as a dropdown (Stable (default) / Experimental = alias `proton-experimental`); `ensure_proton` installs a chosen one (it asks once more for the runtime Steam only names after Proton is installed; Experimental installed unattended on the device in 53 s). A PC VR launch test that fails on stable suggests Experimental (`pipeline.PROTON_TOOL`, `proton_alternative_worth_trying`, button "Try Proton Experimental and reinstall"). Remaining Rick and Morty stutter on head turns = the game rendering below the refresh rate (reprojection), not Proton.
**USB cable link (verified 2026-10-05, cabled to the dev PC):** `usb0` is a USB **NCM** gadget (configfs g1: `ncm.usb0` + `ffs.adb`, Valve 28de:2460) set up by `usb-ncm-gadget@usb0.service`, which only runs with `ConditionPathExists=|/etc/systemd/system/adbd.service.d/steamos-devkit-enabled` = **Developer Mode only**. `usb-ncm-dnsmasq@usb0` serves DHCP with fixed `dhcp-host` entries: Frame 10.86.200.233, PC **10.86.200.234** (`frame/usb.py` FRAME_USB_IP/PC_USB_IP). Windows 11 binds its built-in "UsbNcm Host Device" (no driver); WSL mirrored sees eth 10.86.200.234. USB is high-speed (USB 2.0): upload 36.9 MB/s vs 11.3 MB/s home Wi-Fi. Frame→PC over the cable worked without a firewall change. `scripts/usb_autotest.py` (Windows via powershell.exe from WSL), `frameport frame usb-check`. Wizard "Set up with a USB cable" (`PairingServer(host=PC_USB_IP)`; the real bootstrap ran end to end over USB). Discovery dedupes by SSH host key and prefers USB > Frame hotspot > network (`discovery.dedupe`); a lost address is re-found by key (`Frame.relocate`, tested with a dead saved address).
**Catalog updates without a release (2026-10-05):** apps fetch `catalog/games/*.yaml` from GitHub `main` (`recommend/catalog.refresh_remote`: one API call `git/trees/main?recursive=1` + raw.githubusercontent downloads of changed blobs, cached as `catalog-gh-<sha>.yaml`, every 6 h; GUI at start + Settings → Data "Check now"; CLI background thread + `frameport catalog-update`). `catalog.load()` only reads the cache. A remote entry is skipped (`unusable_reason`) when it names a patch/adapter key this app doesn't register, has a field `CatalogEntry` doesn't know, or `min_app` > this version: add `min_app` (or rely on new patch ids) when a config needs an unreleased FramePort. Remote beats bundled unless the bundled entry has a later updated/verified date; the user's own entries still win as before. Off: setting `catalog.auto_update`, env FRAMEPORT_NO_CATALOG_UPDATE; FRAMEPORT_CATALOG_URL still overrides the source. So: **pushing a catalog change to main reaches users within 6 h** (their recipes follow via catalog_rev → Update on Frame).
**Start activity / QuestCraft / ITR2 pop-in (2026-10-05):** WiiCompiled's VR part (`QuestActivity`, SDL, process `:game`) stays behind Lepton's flat window when the launcher is shown (`device.text_input_window`). `frame.start_activity` (opt-in; analysis `extra.vr_activity` = the original APK's activity with Meta's VR category when it isn't the launcher) gives that activity's filter LAUNCHER and every other LAUNCHER becomes INFO, per element (`axml.set_start_activity`); Lepton's own `apk-info-extractor --print-activity-name` (on the Frame under Lepton/liblepton/apk_extractor) then answers QuestActivity. **OVRPort gives every MAIN activity LAUNCHER + VR categories**, so the VR activity must come from the original APK's analysis, not the converted manifest. Lepton has no activity override (`APP_ACTIVITY` is reset when app_metadata.sh is sourced). QuestCraft reaches Minecraft 1.21.5 (Fabric, Vivecraft, Sodium; LTW "Large Thin Wrapper" GL 3.0 on the Frame's Zink) and stops at `OpenGL error 1282` in `WindowFramebuffer` createTexture (Minecraft's crash report in `files/instances/1.21.5/crash-reports/`, Pojlib's `files/latestlog.txt`); the vrclient SIGSEGV / "pthread_mutex_lock called on a destroyed mutex" afterwards is only the shutdown (Unity's render thread still in vrclient while the instance is destroyed). ITR2 "models popping in and out" in game: Unreal reads user config from **internal** storage (`lepton-data/internal/<pkg>/files/UnrealGame/<Project>/<Project>/Saved/Config/Android/Engine.ini`, not external); `r.AllowOcclusionQueries=0` there broke its menus (removed again). Vulkan shim `vk_query_slots` (two slots per occlusion query) never saw ITR2 create an occlusion query pool, and the run with it crashed (Unreal RenderThread SIGSEGV, caught by sentry-native: no tombstone; the backtrace is in `cache/sentry/*/.sentry-native/*.run/*.envelope` with module offsets) - left off. Next suspect: Unreal 5 mobile HZB occlusion reading depth stored with Valve's FDM injection layer; test = launcher `VK_INSTANCE_LAYERS=''` (Lepton then loads neither VALVE_rpo nor VALVE_fdm_injection, Fossilize still). QuestCraft: LTW overrides glGetError and returns 0 with `LIBGL_NOERROR` set; Lepton passes `LEPTON_ENV_<NAME>` to the app as `<NAME>`, so catalog `lepton_env: {LEPTON_ENV_LIBGL_NOERROR: '1'}` gets Minecraft past the GL error 1282; then black picture (see the catalog entry). FrameBridge logs `new layer` once per layer type per process and projection views only for the first frames, so a second session in the same process (Vivecraft after Unity) needs `layer_debug=1`.
**Vulkan validation / ITR2 solved (2026-10-05):** Khronos' validation layer can't come from Lepton (its layer dir is in the read-only guest image; the Linux copies on the Frame are glibc) and a global `debug.vulkan.layers` property (via the LEPTON_GFXRECON_FP_PROPS trick) kills the container at boot. Working recipe: bundle `libVkLayer_khronos_validation.so` (Khronos android-binaries release, arm64-v8a, stored uncompressed) into a test APK re-signed with the game's key (`apk.sign.sign`), install with `frameport install <pkg> --apk`, and set the Vulkan shim's `vk_validation=1` (it adds the layer at vkCreateInstance; findings under the logcat tag VALIDATION in launch.log, each message ID capped at 10). ITR2's flicker + windows behind models = Unreal's Qualcomm shader-resolve subpasses with a depth resolve of a single-sampled depth attachment (VUID-04908/-03179); `vk_spec_fixes=1` drops that resolve (its TRANSFER_DST half never applies to ITR2: the main depth is transient). Valve's VALVE_rpo layer removed ITR2's fog (catalog `lepton_env: VK_INSTANCE_LAYERS: VK_LAYER_VALVE_fdm_injection`). `r.ViewDistanceScale=2` in the internal Saved/Config/Android/Engine.ini only exists on the owner's Frame (the catalog can't write internal storage yet). Launch tests: Lepton prints a transient "is not a running context" on the first start after an APK change (agent v54 `not_started` waits 30 s for "Boot complete!").
**GitHub #38/#39 (2026-10-05):** PowerWash Simulator stuck at "Waiting.." on a reporter's Frame = Unity sized the right-eye image rect past its swapchain (rect 268+1656 on a 1920-wide swapchain; the runtime's recommended size differs per Frame) and SteamVR rejected every frame (`xrEndFrame failed -25`, XR_ERROR_SWAPCHAIN_RECT_INVALID), after which the game stopped calling xrEndFrame. FrameBridge `rect_clamp` (default on; sizes noted in xrCreateSwapchain; clamped layers count as swapped) keeps projection/quad rects inside their swapchain; triage `swapchain-rect-invalid`. Not reproducible on the dev Frame with `scale` (Unity's eye sizing isn't just the recommended width); no regression there (72 fps). The adapter's revision was NOT bumped (that would mark every installed game outdated): affected users rebuild. The Room VR (#38) = Unity's render thread SIGSEGV in libgallium_dri.so ~30 ms after the game recreates its eye swapchain with samples=4 (FrameBridge retries samples=1); the game's own code turns MSAA on (not OVRManager); candidate fix: hide GL_EXT_multisampled_render_to_texture (GL shim) - needs the APK to test. The launch test passed both (render thread dead / no frames): triage gap.
**Headset round 2026-10-05 (evening):** I Am Cat's judder = repeated xrLocateViews of one display time returning
slightly different poses → FrameBridge `pose_consistency` (owner-verified, works). Lucky's Tale freeze on touching a
save slot = OVRPort's OpenXR dispatcher converting XR_FB_haptic_amplitude_envelope with ns read as s (GitHub #9) →
xrshim `haptic_fix` (owner-verified); its remaining short pauses were the wear sensor ("HMD off/on" 0.5-1 s in
`logs/eyetracking.txt`, not vrserver.txt) → **`focus_hold` is on by default with 5 s** (owner's choice; C defaults
too). The Room VR works (`unity_no_overlay_copy`). BattleSisters (Unity 2019.4 built-in VR, no libOculusXRPlugin.so)
flooded "outside of frame bounds" ~2400/s and hung the GPU (kernel hangcheck, zink DEVICE LOST) → the ovrpshim frame
wait now also applies to Unity 2019 without the Oculus XR Plugin (`UnityOculusCheck.legacy_loop`). Vader Immortal
(UE4, stuck on the loading image after the intro, GitHub #49): VRP repacks carry a Frida gadget (`libfrda.so`,
config `hijack_responses`), but OVRPort's `patch_clean_up_frida` removes its loadLibrary call, so it never runs on
the Frame; `frame.ovr_trace` (opt-in, `native/ovrtrace`: 1138 exported ovr_* stubs → real loader functions, logcat
tag `fp_ovrtrace`: calls, PopMessage answers, unanswered requests every 10 s) is the next diagnostic.
**Unity built-in VR input (2026-10-05):** probe builds (`FRAMEPORT_INPUT_PROBE=1 frameport build …`; it logs
trigger/grip crossings too) showed OVRPlugin returns the full Touch state for every controller mask (also Go masks);
presses reach the games' OVRInput. Accounting+ (Il2CppDumper v6.7.46 reads its Unity 2017 metadata v24, run on Windows)
passes stance selection (NewtonVR grip/trigger) but its motion warning waits for `Input.GetMouseButtonDown(0/1)`,
which Lepton never delivers (no focused Android window) → ovrpshim registers its own
`UnityEngine.Input::GetMouseButtonDown(System.Int32)` icall (il2cpp_add_internal_call, after Unity's: resolve first)
that adds a click in the frame a Touch trigger or A/B/X/Y is newly pressed (`unity_oculus_check` revision 3).
BattleSisters (Unity 2019 InputSystem/XR InputDevices via `VrHandInput`): libunity's Oculus module (OVRPlugin
function table: a global pointer at 0x16b57c0 in this build, slots filled by name, e.g. +0x160 GetControllerState,
+0x168 State2, +0xe8 GetNodePresent) only reports controllers when `strncmp(deviceModel, "Oculus", 6) == 0` (next to
the Go check `deviceModel == "Oculus Pacific"`); Lepton's model is "Valve Lepton" → Go/unknown → only Go masks polled,
buttons dead. `unity_oculus_check` revision 4 (`oculus_model_checks`, Unity 2019 only) turns the 17 compares' length
into 0 (`orr w2, wzr, #6` → `mov w2, #0` after the adrp/add of the "Oculus" literal; the string stays: it is also
Unity's VR device name). Device result: libunity now polls `ovrp_GetControllerState(0x3)` (Touch); owner-confirmed
2026-10-06: buttons work. Its first controller vibration then hit OVRPort's haptic-envelope bug (11 GB, OOM kill) →
`haptic_fix` is now suggested for every game with libOVRPlugin.so (settings detect), BattleSisters works. Ruled out before: ProductName, GetNodePresent, the device-model string itself, exports.
Accounting+ works (owner, 2026-10-06).
**Vader Immortal (UE4, GitHub #49, 2026-10-06, headless):** stuck after the intro on an in-game image (the splash
quad ends ~6 s in; then the game's own projection frames, 72 fps, balanced xrBeginFrame/xrEndFrame). Not the Platform
SDK (`frame.ovr_trace`: only user + entitlement, both answered) and not the repack's Frida gadget (OVRPort's
`patch_clean_up_frida` removes its loadLibrary). It **leaks ~430 GPU mappings (/dev/dri/renderD128) and ~20 MB a
second** (6.5 GB + swap after 5 min, then 26 fps): page-fault stacks (perf -e page-faults, offsets resolved with the
process maps + vrclient.so's own symbols; its text segment is at file offset + 0x4000) end in SteamVR's runtime:
`xrBeginFrame → CSxrCompositorOpenVR::BeginFrame → SubmitExplicitTimingData → CVRCompositorSharedTextures::
BeginGPUTimingCommandBuffer` and `xrEndFrame → CVRCompositorClient::SubmitWithArrayIndexAndTime`. Ruled out: the
layer color scale/bias + image layout structs (FrameBridge `strip_color_bias` 1/2, diagnostic), Valve's Vulkan
layers (VK_INSTANCE_LAYERS=""), array swapchains in general (Lucky's Tale/I Am Cat flat). Kernel tracepoints aren't
allowed for steamos. FrameBridge: `layer_debug` logs xrDestroySwapchain and per-5 s xrBeginFrame/xrEndFrame counts;
`frame_balance` (ends an open frame before the next begin) exists but Vader never leaves one open. Next (built,
not yet run: the Frame slept): `layer_debug` also counts xrAcquire/Wait/ReleaseSwapchainImage per 5 s (hooked only
with layer_debug, after the other conditional hooks) to see whether Vader skips a wait or release: it doesn't (361/361/361 per 5 s).
FrameBridge `snapshot=N` (`snapshot_gl.c`, GLES): every N s the left-eye image the game submits is read back on its
own context and saved as `files/fb_snap_0-7.ppm` (quarter size) — headless launches show a black headset view, this
shows what the game draws. Vader: Lucasfilm logo (an OBB mp4: video works), then its loading card (portrait + segmented
bar) that never advances; the async loader thread sleeps and OBB reads stop (~168 MB of a 2.7 GB pak).
**Lepton's logcat mirror dies (agent v67, 2026-10-09):** occasionally launch.log ends with `logcat: Unexpected EOF!` right after the game starts (about 1 launch in 50, Lepton 2.8.14 and 3.0.5): no dashboard auto-hide, no launch-test result. launch.sh's `_logcat_keeper` then reads `podman exec lepton-steamlaunch-<appid> logcat` itself into launch.log (up to 5 restarts while the game runs).
**Double launch (agent v57, 2026-10-06):** a second Play while Lepton still boots (~10 s with nothing to see) made
the second Lepton stop the first one's container ("Waiting for steamlaunch-<appid> (PID …) to exit", exit 137
"(starting)", "Clearing baked app data due to early exit") and both died (Vader, BattleSisters). launch.sh now takes
`flock` on `<base>/.launch.lock` (fd 9, inherited by Lepton; the watchdog and dashboard helpers close it with
`9>&-`); a second launch exits 0 and logs to `<base>/launch-dup.log`. `upgrade_launchers` adds it to existing
launchers. Verified on the device (second launch during boot: ignored, the first kept running). Vader on its loading
card ignores input too (owner pressed/held every button: presses reach the runtime, the card never changes).
**Issue triage round (2026-10-06, owner's headset):** vibration in OVRPlugin games = 2 s vibrations updated per frame and
stopped with amplitude 0; FrameBridge turns amplitude 0 into xrStopHapticFeedback (else each buzz ran 2 s), haptic_fix
uses the envelope RMS (was its peak), per-game `haptic_scale` → Creed/The Boys/Jurassic World fine. Lambda1VR (TBXR):
loader named by Build.MANUFACTURER (`frame.tbxr_vendor`), no graphics extension enabled (FrameBridge adds
XR_KHR_opengl_es_enable + asks for the requirements on -50), always multisampled render-to-texture (GL shim gives
single-sampled stand-ins when GL_EXT_multisampled_render_to_texture is hidden) + its xash/ data → works. Jurassic World:
`frame.vrapi_stub`. Metro Awakening: contributor's vkshim fixes + hide_space_warp + no VALVE_rpo (jumping polygons like
ITR2). Pinball FX VR: hide_space_warp (stutters). Eleven: a Meta online request fails after platform init → needs Meta
services. Star Wars Tales: top half black + freeze after loading; ruled out: asset-file paks (never requested), Valve
foveation (off: no change), GL errors (MESA_DEBUG=1: none), EGL_BAD_ACCESS once in OVRPlugin init (harmless); the game's
eye image reads back black. BlazeRush: VrApi bridge exports + ovr*_ToString stubs + avatar stub get it to the menu room
at 72 fps, full input reaches it (diagnostics `input 5s`: Touch type only, sticks 1.0, buttons, poses 0x8f), but the room
draws no controllers and ignores input; avatar loader forced to its "Failed" path (no logged-in user) changed nothing.
`frame.ovr_trace` can't trace Unity games (P/Invoke dlsym; nothing imports ovr_*). Headless: the VrApi bridge's 30 s
head-pose deadline ends VR mode without a worn headset (not a game bug).
**Lepton storage (2026-09-30):** each app's /sdcard (= /storage/emulated/0 → `<base>/lepton-data/external`) has `Movies`/`Download`/`Documents` symlinked to the Frame's `~/Videos`/`~/Downloads`/`~/Documents` (liblepton/mounting.sh, only if they exist at start); agent v24 `storage_targets` reads that mapping. Android's MediaProvider canonicalises paths to /home/steamos/... and rejects every file ("doesn't appear under [/system/media...]"), `sm list-volumes` is empty: the media index never works, apps must browse folders. Lepton installs with `adb install -g` (runtime permissions granted, MANAGE_EXTERNAL_STORAGE too). Files: `install/files.py`, `frameport frame send|storage`, GUI Files tab (formerly Frame → Send files).
**SteamVR per-app settings (2026-09-30):** editing steamvr.vrsettings while SteamVR runs is lost; the web API (127.0.0.1:27062 /app/setsettings) needs `x-steamvr-secret`. `native/vrsettings` = `fp_vrsettings.exe` (freestanding, OpenVR `FnTable:IVRSettings_003` as a Utility app, loads SteamVR's bin/win64/openvr_api.dll) sets them live and SteamVR persists them: section `steam.app.<shortcut appid>`, keys `preferredRefreshRate` (float) and `motionSmoothingOverride` (0 global, 1 on, 2 off, 3 always). Steam Link (vrlink) lists the Frame's rates 72/80/90/96/108/120/144 in vrserver.txt and follows the per-app preference ("host preferred N Hz"; whether the key is honoured is unverified in-headset yet). Judder metric: vrcompositor.txt session summary dropped + "Timed out. N total" (Stormland: 0 dropped but 313 timeouts in 2 min); fpsVR (`%LOCALAPPDATA%\fpsVR\*.json`, 0.1 ms histograms) gives p99 CPU/GPU ms. `pcvr.steamvr_tuning` (default on, PC only) applies on Play: highest rate whose budget ≥ p99×1.05, at least one step down, smoothing on.
**Language packs (merged from PR #20, 2026-10-04):** overport's `libovrplatformloader.so` is a dispatcher that `dlopen`s Meta's own loader (`libovrplatformloader_meta.so` / `_meta_q1.so`, also `libpxrplatformloader.so`) and keeps its own message queue; `ovr_LanguagePack_GetCurrent/SetCurrent` are 8-byte `return 0` stubs in it, `ovr_AssetFile_GetList` forwards to Meta's loader. `frame.langpacks` (opt-in, `native/langpack`) serves `<tag>.lang` files from the game's data; `elf.hide_exports` marks the loader's exports STB_LOCAL (bionic and glibc only match GLOBAL/WEAK; verified for glibc, bionic's `is_symbol_global_and_defined` is from memory). `libfp_langpack.so` is built here (`python native/build.py --only langpack`) and committed. Owner-verified 2026-10-04: Deadpool VR with only `en.lang` and the patch on plays English dialogue and runs normally (headless launch tests show 2-6 fps while it loads: not a regression sign). A dispatcher answer that arrives after we answered the timed-out GetList is dropped (one answer per request); games already in a library get `lang_packs` filled after an app update (`library._refresh_data_fields`). The library logs to logcat under the tag `fp_langpack` (dirs looked in, packs found, every language-pack call), so it shows up in the game's `launch.log`; an `ovr_AssetFile_GetList` the dispatcher leaves unanswered for 1.5 s is answered with our packs alone. Deadpool VR (Unreal) accepts a pack only when its `Metadata` equals the game's own version string (`ULanguagePacksSubsystem` compares it with `%s.%s.%s.%s.%s` built from the build info, e.g. `1.0.40.356975.Quest` = versionName; found by disassembling `libUE4.so`): the patch writes the APK's versionName into the library (`@FPMETA@` slot, `with_metadata`), `FRAMEPORT_LANGPACK_META` overrides it. Deadpool VR (2026-10-04, headset): German became selectable with that Metadata, but dialogue stayed silent (even English once reported as a pack) while the path was spelled `/sdcard/Android/obb/<pkg>/x.lang`; with the `/storage/emulated/0/Android/obb/<pkg>/x.lang` spelling (Unreal's own, now listed first in `scan_dirs`) German dialogue plays. `FRAMEPORT_LANGPACK_SKIP=<tags>` or a file `fp_langpack_skip` in the obb folder leaves packs out of the list (experiments).
**Cube swapchains (GitHub #107, 2026-10-09):** the Frame's runtime refuses `faceCount=6` swapchains (-2,
XR_ERROR_RUNTIME_FAILURE); OVRPlugin ignores that ("CreateSwapchain for eye 0: 0x0, 0 stages") and crashes in
ovrp_EndFrame4 (memset). FrameBridge `cube_standin` (default on, `native/adapter/cube_standin.c`) serves a refused cube
swapchain as one GL cube-map texture in the app's context (GLES only) and drops its layers. Verified headless with
Budget Cuts Ultimate (2048² sRGB, 12 mips; runs on at ~70 fps); what the cube layer showed is simply missing.
**Hardware video decoding (PR #96, PR #128 by Lucas-Mathieu, adapted 2026-10-10, agent v71):** `native/hevc` = one
OMX plugin `OMX.frameport.{avc,hevc,vp9}.decoder` (FFmpeg v4l2m2m on Iris /dev/video-dec0, FFmpeg software decoders as
fallback inside the component, Vulkan copy for big native surfaces). The connection installs it once per Frame
(`ensure_video_codec` → agent `video_codec_status`/`install_video_codec`: `~/.local/share/frameport/video-codec/versions/
<manifest sha>` + `current` symlink). A Frame keeps the same or a newer `revision` (no flip-flop between PCs) → **bump
`revision` in native/hevc/build.py with every artifact change**; a failed install isn't retried during the connection.
Per game: only launchers of games whose recipe has `frame.hw_video_decode` (install stage, no APK change; suggested
from analysis `media_codec`, ANALYSIS_VERSION 8; deployment.json `hw_video_decode`) get the codec line → the Podman
wrapper (native/hevc/podman.py) mounts the plugin into that container (merged media_codecs.xml in
$XDG_RUNTIME_DIR/frameport-video). Off for every game: Settings → Installing (library `video.hw_decode` → agent
`video_codec_switch` = video-codec/disabled); one game: `FRAMEPORT_NO_HW_VIDEO=1 %command%`. `upgrade_launchers`
converts agent ≤70 launchers (Batman's `<base>/frameport-codec` → keeps the line, folder then removed). Batman: catalog
+ migration `batman_video_patches` (`frame.hw_video_decode` + hidden adapter setting `surface_native`). Iris: 8K
refused (ENOMEM) while any other decoder session is open; SteamVR's vrlinkrunthread holds one ~12 s at game start →
refused opens retry until 20 s after the plugin loaded (else 2 s), then software; VP9 7680x3840 never returned a
picture → VP9 ≤4096x2304; hidden VP9 frames come back as empty capture buffers (bytesused 0, no LAST):
FFmpeg's wrapper ended the EOS drain at the first one (two-pass VP9 lost its last ~25 frames) → build.py requeues
them (codec revision 8; drain ends at LAST, or 1 s after a skipped empty buffer; dev Frame 2026-10-10: 600/600 =
OMX.google.vp9 Y hashes). Rebuilds are deterministic (ext4 + NTFS path
with spaces, two NDK copies → same; rev 8 141de01f…; PR #128's own sources → its 27a2d749…). Not yet run on the device.
**Vivox API 31 (GitHub #101, 2026-10-09):** newer Vivox builds (Green Hell VR) call Android 12 AudioManager
communication-device methods from `com.vivox.sdk.AudioChangeListener` with no SDK check → NoSuchMethodError on Lepton's
Android 11. `frame.vivox_audio_route` (analysis `vivox_api31`, ANALYSIS_VERSION 4) makes every such method return at
once (`Dex.return_early`: return-void / `const/4 v0,0; return v0`; nopping the invoke would leave a move-result the
verifier rejects). Older Vivox (Eleven Table Tennis, BattleSisters) lacks that code and isn't matched. Verified
headless: Vivox initialises, 150 s at ~65-70 fps.
**Multiview programs on flat framebuffers (GitHub #77, Doom3Quest, 2026-10-09, prototype):** Mesa enforces OVR_multiview's
"program num_views == draw framebuffer views" rule (`draw_validate.c`, the draw is dropped silently); Qualcomm doesn't.
Doom3Quest compiles every VS with `layout(num_views=2) in;` and draws its HUD/PDA into 2D-texture FBOs → black. Opt-in
`frame.gl_multiview_fbo` (analysis `gl_multiview_libs`, ANALYSIS_VERSION 6; own-engine GLES only): `native/glmv` =
`libfpglmv.so` (12 chars = "libGLESv3.so": libdoom3.so's one `.rodata` dlopen string is rewritten in place, its qgl*
table comes from dlsym on that handle; also first DT_NEEDED for its direct gl*/egl* imports). Such draws use a lazily
built single-view twin (view 0, uniforms copied per draw); eglMakeCurrent resets the per-thread cache. Host-tested only
(rewriter on all 19 Doom3Quest shaders + glmv.c against a stand-in GL, `tests/test_gl_multiview_fbo.py`); the host's
Mesa 23.2 llvmpipe has no OVR_multiview. Headset-verified by Xandrix1987 (2026-10-09: HUD/PDA shown, no fps drop) -> in the Doom3Quest catalog recipe.
**Session triage (agent v70, 2026-10-09):** launch tests never reach FOCUSED, so real play sessions are triaged
too. list_installed gives each game `last_play` {start, end, test} from `<anchor>/plays.log` (launch tests write a
`test <unix>` line first → test sessions are only marked); `session_log` returns the newest session's launch.log
(`<base>/session.log`, ≤4 MB: head + tail + FrameBridge/crash lines between) + that session's logcat-crash.log +
`journalctl -k` GPU lines ("kernel: …"). The GUI's connection refresh (`app._check_sessions` → `pipeline.sessions_due`,
background thread; sessions >7 days old are skipped) runs `pipeline.triage_session` = `validate/session.analyze`
(triage.yaml signatures incl. `space-warp-used` (info, `question:`, never auto-applied), `gpu-hang` (`report: true`)
+ computed `slow-frames` (pacing windows vs the nearest refresh rate) and `focus-dips` (FrameBridge always logs
`focus: lost` / `focus: back after N ms`, session_fixes.c)) → library `last_session` / `last_session_checked` → game
page "Last session" callout (Try this fix / Rebuild with this fix / Yes-No question / Report / Dismiss). Suggestions may
be values (`adapter.scale=0.85`, `triage.split_suggestion`); adapter-only fixes are pushed live (`apply_suggestions_live`
→ agent set_settings, like the Game settings dialog). CLI `frameport session <pkg> [--apply]`. PC VR (Proton) launchers
log no session end, so they aren't triaged yet. pac_hints stays triage-only: a survey of all 68 dump APKs found unpaired
PAC hints in 21 libraries of 18 games (OpenSSL's 38/40 in most UE4 libUE4.so and libEOSSDK.so, UE5 libUnreal.so ~400
vs +2-3, libass, libopencv, …), most of them games that work, so default-on would rewrite many working builds.
**Unresolved (as of 2026-09-28):** Arcsmith (right-eye distortion) and Time Stall (both eyes) — swap, tracking, Valve
layers, depth, pacing ruled out. Sniper Elite VR (DEVICE LOST), Espire 1 (Mesa GL upload crash), HITMAN 3 (freedreno
crash): use PC versions.
**Install links / FrameDrop button protocol (2026-10-07, not yet clicked end to end from a browser):** FrameDrop
(framedropvr.com, a closed-source Windows sideloader) defines "Install with FrameDrop" buttons:
`https://framedropvr.com/install?manifest=<url>|url=<file>` → that page opens `framedrop://install?…` (1.6 s, else its
home page); manifest `{"schema":"framedrop.install/v1","name","files":[{"url","sha256"}]}` (name = Steam title; .apk
or Linux .zip). `deeplink.py` (no Flet) parses framedrop://, frameport:// and the pasted https link, enforces its
rules (https; http only on loopback; no credentials; no LAN/loopback/link-local IPs, also after DNS and redirects; URL
ends in a file name), caps manifests at 256 KiB, ignores non-hex sha256 (FrameDrop's own example has a placeholder),
downloads into `<data>/downloads/<slug>-<hash>/` (OBBs → `obb/` next to the APK, `.part` removed on cancel/mismatch);
`pipeline.add_from_link` routes APK / Linux / exe and sets `title` + `title_locked` + `link` (a bare file link keeps
FramePort's title). GUI: `views/link_dialog.py` (always asks first), Add games → "Install from a link…", CLI
`frameport open-link [--yes --no-install --gui]`. **A `flet build` bundle can't take a URL argument** (the Flutter
host treats any argv as a developer page URL), so `urlhandler.py` registers a script, not FramePort.exe: Windows
HKCU `Software\Classes\{framedrop,frameport}` → hidden PowerShell `frameport-link-handler.ps1`; WSL (source runs)
the same keys → `wsl.exe -d <distro> -e sh frameport-link-handler.sh`; Linux `frameport-links.desktop` +
`xdg-mime`; macOS unsupported (Apple Events, paste instead). The script drops the link into `<data>/links/*.link`
and starts FramePort unless `<data>/gui.alive` is < 10 s old (`gui.starting` stops double starts); the GUI's
`_watch_links` thread touches the heartbeat and opens links (newest window session). Settings → Install links: one
switch per scheme (`links.framedrop`, `links.frameport`, default on); a scheme another program owns (FrameDrop) is
only taken with "Use FramePort for these links" (`register([s], force=True)`); off removes only FramePort's own
registration (`MARK` in the command). Never registered with FRAMEPORT_HOME/FRAMEPORT_NO_LINK_HANDLER (tests,
screenshots). Same round: files dropped on the Library (`ui/dropped.py`, bundles only like the Files tab), "Add a
Windows program (.exe)…" (`pipeline.add_windows_exe`: exe in Downloads/home/drive root copied alone into
`<data>/windows-apps/<slug>/`), patch `device.display_mode` (Automatic / VR / Flat window → `InstallContext.display`,
`installer.show_window`). FramePort-only manifest extension `"frameport": {"description", "icon"}` (bad values ignored; icon: same URL rules,
≤2 MiB, Pillow-checked, ≥32 px, saved as PNG in `<data>/downloads/icons/`, shown in the question by asset URL, then
`sources.apply_custom(pkg, "icon")` unless `.picked` exists; description fills `details.description` only when
empty). Bare file links get a title guessed from the file name (`title_from_filename`: version/arch dropped, package
names → last part). Windows test of 0.12.1.dev191 (2026-10-07): a button click opened the dialog; but a click right
after closing FramePort did nothing (the closed window's heartbeat was < 10 s old) → the handler scripts now wait
up to 4 s for the link file to be taken before trusting the heartbeat, the window's CLOSE event / atexit delete
`gui.alive`, and the Windows command runs under `conhost.exe --headless` (plain `-WindowStyle Hidden` flashed a
console). Screens: `scripts/ui_smoke.py --links --fake-frame --game <pkg>` (tall pages: `--viewport
1280x7000`; Flutter's popup menu ignores Escape).
## Releases, CI, GitHub
Maintainer-only notes (accounts, credentials, key locations) live in the git-ignored `CLAUDE.local.md`.
Public repo `github.com/spoopyghosty0/frameport` (branch `main`). Push a `v*` tag → CI (`.github/workflows/build.yml`)
tests, builds Windows x64 / macOS arm64 / Linux x64 bundles, signs, attests and publishes a GitHub Release
(`FramePort-*.zip/.tar.gz`, the CLI wheel `frameport-<ver>-py3-none-any.whl`, `SHA256SUMS.txt`,
`FramePort-selfsigned.cer`; notes = "What's new" from the annotated tag message + `docs/INSTALL.md` from "First launch").
`FramePort-selfsigned.cer`; notes = "What's new" from the annotated tag message + the short `packaging/release-footer.md`; owner: keep release
notes short — a few "What's new" bullets, nothing long after them).
Installed apps find the release themselves (self-update), so the notes are what users see in the update dialog.
- **Dev builds (for testers, no release):** Actions → build → Run workflow (main), "dev" ticked, optional "notes"
(what to test). The bundles get version `<next patch>.dev<run number>` (`scripts/dev_version.py`, not committed) and
replace the rolling `dev` pre-release (`dev-release` job; same assets + SHA256SUMS). Automatic update checks ignore
pre-releases; testers use Settings → Updates → "Install the latest dev build…" (`updates.check_dev`,
`Updater.install_dev`). `parse_version` sorts 0.9.0 < 0.9.1.devN < 0.9.1, so testers get the next release normally.
- **Upstream trackers:** issues labelled `upstream` (#73 microphone, #74 haptics, #75 VrApi bridge) list our workarounds for OVRPort bugs and how to drop them; check them against OVRPort's latest release before each release.
- **Release checklist:** bump `src/frameport/_version.py` (the only version; `scripts/package.py` fails a tag build
whose tag ≠ `v<_version>`), commit, `git tag -a vX.Y.Z -m "FramePort X.Y.Z" -m "<What's new, Markdown bullets>"`,
push the commit and the tag. Never publish a release without its `SHA256SUMS.txt` (the updater refuses it) and keep
@@ -335,22 +760,32 @@ Installed apps find the release themselves (self-update), so the notes are what
- Signing is **free/self-signed by the owner's choice** (no paid certs, no SignPath): Windows binaries are signed with
a self-signed "FramePort (self-signed)" code-signing cert (RSA 3072, valid to 2031, SHA-256
`4E:12:98:91:62:C0:E4:50:FB:65:1D:34:BB:73:00:09:7B:78:BE:88:5C:A7:6C:42:23:46:9B:92:A1:59:A7:6E`); secrets
`WINDOWS_CODESIGN_PFX` (base64) + `WINDOWS_CODESIGN_PASSWORD`. Private key: `~/.config/frameport-signing/` (WSL) and
the backup `PATCHED/_signing-keys/frameport-app-codesign/` — never commit it. macOS is ad-hoc signed only (Gatekeeper
`WINDOWS_CODESIGN_PFX` (base64) + `WINDOWS_CODESIGN_PASSWORD`. The private key is never committed (its
location is in `CLAUDE.local.md`). macOS is ad-hoc signed only (Gatekeeper
needs right-click → Open; notarization would need the paid Apple program). Users still see SmartScreen unless they
import the .cer into Trusted Root.
- CI gotchas: `flet build` needs `--yes --no-rich-output` (it prompts to install Flutter; rich output crashes the
Windows console) plus PYTHONUTF8; macOS builds need `--python-version 3.12 --arch arm64` (cryptography has no wheels
for flet's default Python / x86_64 cross-build), with a PyInstaller fallback step; `astral-sh/setup-uv` has no
floating major tags after v7 → pin the exact version; force-moving a tag starts duplicate runs (cancel one).
- **This project's GitHub identity is `spoopyghosty0`** (a dedicated account; the machine's default gh/git login is a
different, personal account that must never touch this repo). `gh` (`~/.local/bin/gh`) uses it through
`GH_CONFIG_DIR=~/.config/gh-spoopyghosty0` (set for Claude Code in the git-ignored `.claude/settings.local.json`);
git pushes from this folder authenticate as it through a repo-local credential helper, and commits use the repo-local
identity `spoopyghosty0 <336754034+spoopyghosty0@users.noreply.github.com>`. Check with `gh api user --jq .login`
before any GitHub action.
- **No Claude trailers** (`Co-Authored-By: Claude …`, `Claude-Session: …`) in commits or PR descriptions — the owner's
rule; history was rewritten to remove them.
- `jni` (2026-10-06): jni_flutter 1.0.4/1.0.4+1 generate bindings that require jni ^1.1.0 while Flet's build template
pins jni 1.0.0 → every `flet build` bundle failed (`JniVersionCheck`, "generated bindings expect package:jni
^1.1.0"). pyproject `[tool.flet.flutter.pubspec.dependency_overrides] jni = "1.1.0"` fixes it (pinning
jni_flutter 1.0.4 does not); drop it once Flet's template moves to jni 1.1. A failed tag build publishes nothing:
delete and re-push the tag on the fixed commit.
- macOS runner (2026-10-02): `macos-latest` jobs went unassigned (cancelled after 15 min, no steps); `macos-15`'s Xcode
16.4 fails a Flutter plugin (`NWPath has no member`); `macos-26` (Xcode 26) builds with `flet build`. The PyInstaller
fallback (`package.py --pyinstaller`) passes `--yes` so a failed `flet build`'s folder doesn't stop it at a prompt.
- Windows PowerShell calls from Python (`updates._powershell()`): use `%SystemRoot%\System32\WindowsPowerShell\v1.0\
powershell.exe` with `PSModulePath` removed from the environment — started under PowerShell 7 (CI's default shell,
or a user's pwsh terminal) it couldn't run Get-AuthenticodeSignature (v0.3.0's Windows update smoke failed on it).
`v0.3.0` is a tag without a release (that failed build); the updater shipped first in v0.3.1.
- **Never start PowerShell with `DETACHED_PROCESS` from the packaged app**: it exits 0 without running anything (found
in the 0.3.1→0.3.2 end-to-end test: the app quit, nothing updated). `updates.spawn_hidden` = CREATE_NEW_CONSOLE +
hidden window; `apply()` waits until the script has logged that it runs and raises otherwise (the app then stays
open). Windows installs of 0.3.1/0.3.2 can't update themselves: they need one manual download.
- The Linux bundle is built on ubuntu-22.04: a 24.04-built Flutter bundle needs GLib 2.80 (`undefined symbol:
g_once_init_enter_pointer` on 22.04).
- **The repo is public: never commit personal data** — the Frame's IP address, the Steam user id, the owner's email,
local home paths (native builds use `-ffile-prefix-map`). History was rewritten once to remove them.
@@ -373,13 +808,16 @@ GLAD/GLES); Unreal → alternate no-ForceQuit build. Score changes with
- Reinstalls keep one rollback copy (`<base>/previous-game.apk`, `settings.conf.previous`); `frameport frame cleanup`
removes them (and `--path ~/X` extra folders under home).
## Project status (2026-09-29)
## Project status (2026-10-02)
Self-update, the Files tab, OVRPort 1.2.5, non-Quest Android apps (vr_kind) and GUI localisation (tr(), 0.3.x) are
in; see the sections above. Earlier state (2026-09-29):
34 Quest games ported; the owner confirmed in the headset that all FramePort-rebuilt games work: 23 work, 5 work with
issues (Arcsmith/Time Stall eye distortion, AC Nexus some flipped launch text, Phantom DLC button, Silhouette hands),
6 can't run (Sniper Elite VR, Espire 1, HITMAN, and the 32-bit Journey of the Gods / Shadow Point / Sports Scramble).
Parity: all 34 rebuilt from the dumps match the known-good builds (`docs/parity-report.md`) and were reinstalled +
Parity: all 34 rebuilt from the dumps match the known-good builds (`docs/parity-report.md`, generated locally and
git-ignored; 34/34 again with OVRPort 1.2.5 on 2026-10-02) and were reinstalled +
launch-tested with 0 regressions (`docs/parity-device-report.md`). `PATCHED/` holds exactly the installed builds.
Owner preferences: manual installs (no FrameDrop, no Quest2Frame app), Python + Flet, dynamic data over hardcoding,
Owner preferences: manual installs (no third-party installer apps), Python + Flet, dynamic data over hardcoding,
free tooling only, public repo scrubbed of personal data, keep the known-good backups.
Rift/PC VR support (2026-09-29): implemented + unit-tested, not yet tried with a real Rift game on the PC or Frame
(needs a Rift dump, and Proton installed on the Frame). Open ideas: exe-icon artwork for Rift games, macOS x86_64 bundle, USB-cable connection (Frame `usb0`, untested),
+8
View File
@@ -0,0 +1,8 @@
# Code of conduct
This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
In short: be respectful and constructive, assume good faith, and keep discussions about the project. Harassment and
personal attacks aren't tolerated.
Report unacceptable behaviour privately through a GitHub security advisory on this repository (it reaches the
maintainer only). Reports are handled confidentially.
+54
View File
@@ -0,0 +1,54 @@
# Contributing
Thanks for helping. The quickest contributions:
- **A game works on the Frame?** In FramePort: the game's menu → **Share working config…** opens a prefilled issue
with its recipe. Accepted configs become built-in recipes.
- **Something doesn't work?** The game's menu → **Report a problem…** saves a diagnostics zip (personal data
removed) and opens a prefilled issue to attach it to.
## Development
```
uv sync --extra dev # Python 3.11+, uv (https://docs.astral.sh/uv/)
uv run frameport-gui # the app
uv run frameport --help # the command line
uv run pytest # tests (no headset or game files needed)
uv run ruff check . # lint
```
- Code and architecture: `CLAUDE.md`, `docs/ARCHITECTURE.md`; per-game symptoms and fixes: `docs/PLAYBOOK.md`.
- Interface wording: `docs/STYLE.md`. GUI texts go through `tr()`; after changing them run
`python scripts/i18n_extract.py`.
- Translations: see [Translating FramePort](#translating-frameport) below.
- New fixes are patch modules (`src/frameport/patches/`), with a triage signature (`catalog/triage.yaml`), a PLAYBOOK
row and a unit test.
- Native binaries in `artifacts/` are rebuilt with `python native/build.py` (downloads the NDK).
## Adding a tested game
Tested a game on the Steam Frame? The easiest way is in FramePort: open the game → **…** → **Share working config…**.
It opens a prefilled GitHub issue with the exact recipe; after review a workflow turns it into
`catalog/games/<package>.yaml`. Without the app: [working config form](https://github.com/spoopyghosty0/frameport/issues/new?template=working-config.yml). Something doesn't run: the game's
**Report a problem…** (diagnostics zip, personal data removed) or the [problem report form](https://github.com/spoopyghosty0/frameport/issues/new?template=bug-report.yml).
After catalog changes, regenerate the games list: `python scripts/compat_list.py`.
## Translating FramePort
The app's texts (screens, help, patch and setting descriptions) can be translated; the command line, logs and
diagnostics stay English. No programming needed:
1. Copy `src/frameport/locales/template.json` to `src/frameport/locales/<code>.json`, where `<code>` is the language
code (`de`, `fr`, `pt`, `ja`, …).
2. Add `"_language": "<the language's own name>"` (e.g. `"Deutsch"`); it's shown in Settings → Language.
3. Fill in the values. Each key is the English text; leave a value empty to keep the English text. Plural entries
have a list value: `["<one>", "<other>"]`. Keep `{placeholders}` such as `{title}` or `{n}` exactly as they are,
and keep `…`, `·` and line breaks where the English has them.
4. Try it: `uv run frameport-gui`, choose the language in Settings → Language, restart FramePort.
5. Open a pull request with the file. When the English texts change, `python scripts/i18n_extract.py` refreshes the
template; new texts then show in English until they're translated.
Wording rules for English (and a guide for tone) are in `docs/STYLE.md`.
## Ground rules
- Use only games you own. Contributions that help bypass DRM, licence or entitlement checks, or that add game files,
are not accepted.
- Never commit personal data (IP addresses, user names, home paths, Steam IDs).
- By contributing you agree to license your work under GPL-3.0-only.
+142 -29
View File
@@ -1,38 +1,151 @@
# FramePort
Play your Meta Quest standalone games on the **Valve Steam Frame**. FramePort patches a Quest APK so it runs in the
Frame's Lepton Android runtime, validates the result, installs it over Wi-Fi and adds it to your Steam library with
artwork. Think Morphe/ReVanced Manager, for Quest → Steam Frame:
[![Release](https://img.shields.io/github/v/release/spoopyghosty0/frameport)](https://github.com/spoopyghosty0/frameport/releases/latest)
[![Build](https://img.shields.io/github/actions/workflow/status/spoopyghosty0/frameport/build.yml?branch=main)](https://github.com/spoopyghosty0/frameport/actions/workflows/build.yml)
[![Downloads](https://img.shields.io/github/downloads/spoopyghosty0/frameport/total)](https://github.com/spoopyghosty0/frameport/releases)
[![License](https://img.shields.io/github/license/spoopyghosty0/frameport)](LICENSE)
![Platforms](https://img.shields.io/badge/platforms-Windows%20%7C%20macOS%20%7C%20Linux-blue)
![Steam Frame](https://img.shields.io/badge/Steam%20Frame-supported-1b2838?logo=steam&logoColor=white)
1. **Connect your Frame** once: the app shows one command to paste into the Frame's desktop terminal (it turns on SSH,
trusts the app, and installs Lepton). After that the app finds the Frame on your network by itself.
2. **Add games**: scan a folder of Quest dumps (APK + OBB) or add an APK.
3. **Review patches**: every game gets suggested patches (overport's plus Steam Frame fixes), each with a reason.
34 games have verified recipes; unknown games get heuristics.
4. **Patch, validate, install**: signature/alignment/dependency checks, upload (resumable, skips data already on the
Frame), Steam shortcut + artwork, and a headless launch test with log triage that suggests fixes.
Install games that target the Meta Quest, Android, or general PCVR onto your **Valve Steam Frame**. FramePort handles everything from uploading game files, setting up your Frame, injecting compatibility patches, and adding shortcuts to your Steam library. FramePort aims to be as simple as possible by taking advantage of the fact that the Steam Frame runs on Linux.
FramePort downloads and manages its own tools (Java runtime, [overport](https://github.com/ovrport/app) CLI,
apksigner). Nothing is installed system-wide, and no Android SDK/NDK is needed.
![Library](docs/images/library.png)
## Install
- **App bundles**: download from [Releases](https://github.com/spoopyghosty0/frameport/releases) (Windows x64, macOS
Apple Silicon, Linux x64); see `docs/INSTALL.md` for the first-launch warning (self-signed / ad-hoc signed) and
how to verify a download. Built by CI (`.github/workflows/build.yml`, `flet build`). FramePort **updates itself**:
when a new release is out, click **Update now** in the Library (or run `frameport update`).
- **Command line only**: `uv tool install <the release's frameport-*.whl link>` (or pipx / pip), then `frameport --help`.
- **From source**: `uv sync && uv run frameport-gui` (CLI: `uv run frameport --help`).
> **Notice:** FramePort explicitly does NOT download, share, or unlock games. You must provide legally obtained game
> executables. Core features of FramePort simply download and wrap other published tools (see [Built on](#built-on))
> with patches provided by FramePort adding a hardware compatibility layer. This enables users to use games/apps legally
> purchased on sites like [SideQuest](https://sidequestvr.com/).
## Status of tested games
See `catalog/games/` (and the Library screen): 23 work, 5 work with issues, 6 can't run on the Frame (3 are 32-bit
only; PC VR alternatives are listed). Details and how problems were solved: `docs/PLAYBOOK.md`.
All 34 recipes were verified by rebuilding from the original dumps (`docs/parity-report.md`: 34/34 match the
hand-made known-good builds) and reinstalling + launch-testing on a Frame (`docs/parity-device-report.md`: 0 regressions).
## Features
## Legal
Use only with games you own. FramePort does not download games. It is GPL-3.0-only because it bundles code derived
from GPL-3.0 projects (Quest2Frame's hook technique in the adapter, the Android-XR-Bridge/OVRPort VrApi bridge).
overport is downloaded from its official releases and is not redistributed.
- **Painless setup:** one short command on the Frame. No root, no `sudo`, no password.
[What it changes](docs/FRAME_SETUP.md).
- **Type on Frame:** use your computer's keyboard on the Frame: in VR apps, Android apps, Steam and the desktop.
[More](#type-on-frame).
- **One click per game:** convert, patch, sign, upload, add to Steam with artwork, launch test. Artwork that can't be found automatically can be picked from the stores or replaced with your own images.
- **Per-game recipes:** a tested catalog plus detection rules; every patch explained in plain words.
- **FrameBridge:** FramePort's OpenXR adapter emulates what the Frame natively lacks (passthrough, room, controller models,
curved and 360° layers); game settings as simple switches.
- **Beyond Quest:** Android apps as windows, PC VR via Proton or Revive, Windows (non-VR) games via Proton, a Files
tab with drag and drop.
- **Linux apps:** install Linux apps (AppImage, a folder, or a zip/tar archive) on the Frame with a Steam
shortcut; arm64 builds run natively on SteamOS, x86_64 builds through Valve's FEX translator.
- **Install links:** "Install with FrameDrop" buttons on web pages (the one-click protocol of the FrameDrop
sideloader) and pasted links open in FramePort, which asks, downloads, adds and installs the build.
- **Screenshots tab:** the screenshots you took in the headset, sorted by game (matched by play time) and day;
view them and download them to your computer.
- **Live view tab:** watch what the headset shows, with sound, in a browser window on your computer.
- **Monitor tab:** the running game's frame rate, the Frame's load, temperatures, power and battery live, and its
processes, which you can end. [More](#monitor).
- **Self-updating** releases, redacted diagnostics, one-click problem reports and working-config sharing.
## Quick start
1. [Download](https://github.com/spoopyghosty0/frameport/releases/latest) and unzip the build for Windows, macOS
(Apple Silicon) or Linux, then start FramePort.
2. **Connect the Frame** (once):
1. In FramePort click **Steam Frame → Show setup command**. Keep FramePort open; the Frame and your computer must
be on the same Wi-Fi.
2. On the Frame open the **SteamVR dashboard → Launch a program → Desktop**: the Linux desktop opens on a virtual
screen.
3. Open the app menu (bottom-left corner of that desktop) → **System → Konsole** (or search for Konsole).
4. Type the command FramePort shows exactly as shown (on-screen keyboard or any USB/Bluetooth keyboard) and press
**Enter**. This will run the following [bash setup script](bootstrap/bootstrap.sh).
5. After a few seconds the desktop closes by itself (Steam restarts once); that's expected. If
Steam asks to install **Lepton**, confirm it. FramePort shows the Frame as connected within a minute. No
password needed.
3. **Add games → Scan a folder** with your game backups (APK + OBB, or PC VR game folders).
4. Open a game → **Install on Frame**, then play it from the Frame's Steam library.
Full guide, firewalls and troubleshooting: [docs/INSTALL.md](docs/INSTALL.md). Questions (e.g. how to lay out games
with OBB files): [docs/FAQ.md](docs/FAQ.md).
## Type on Frame
Typing in VR is painful, so FramePort turns your computer's keyboard into a keyboard for the Frame. Open **Type on
Frame** (its own tab in the sidebar), select a text field in the headset and type: searches, logins, chat, in any
app, in Steam or on the desktop. Paste longer text to type it in one go. Nothing to install: FramePort adds a virtual
keyboard on the Frame while the tab is open, without root.
![Type on Frame](docs/images/type-on-frame.png)
Unity apps whose text fields close the moment you select them on the Frame (no system keyboard there) get a per-game
fix, so Steam's on-screen keyboard and Type on Frame work in them too.
[Details](docs/INSTALL.md#typing-on-the-frame).
## Screenshots
Screenshots you take in the headset show up in FramePort's **Screenshots** tab, grouped by day and matched to the game
you were playing. Open one full size, step through them, and download single shots, a selection or all of them to
your computer.
![Screenshots](docs/images/screenshots.png)
![Screenshot viewer](docs/images/screenshot-viewer.png)
## Live view
The **Live view** tab streams what the headset shows, with its sound, to your computer: click **Start live view** and
it opens in your default web browser (full screen with a double-click; click **Sound on** to hear it, as browsers start
videos muted). Pick 360p to 1080p, or the headset view's full size. The picture comes from SteamVR's built-in headset
view on the Frame and is encoded there while you watch (about one CPU core), so stop it when you're done. It's black
while the headset sleeps.
## Monitor
The **Monitor** tab shows what the Frame is doing while it's open: the running game with its frame rate against the
display's refresh rate, CPU, graphics chip, memory, the hottest temperature with the fan speed, power draw and battery
time left, each with a 2-minute chart. **Show details** adds every CPU core, all temperature sensors, where the power
goes and the network. Below, the game's processes (or Steam's, or all of them) with their CPU, GPU and memory use:
right-click one to end it, or end the whole game. Programs that Steam, SteamVR or the desktop need are marked and ask
again. The Frame sends the numbers itself (about 1 % of one CPU core) and stops when you leave the tab.
![Monitor](docs/images/monitor.png)
## Compatibility
If a game has already been tested with FramePort, it will automatically use the optimal game config. Otherwise, FramePort
will attempt to guess key patches. If you find a new config that works for an app you are testing, please consider submitting it to the community!
**[List of tested games](docs/GAMES.md)**
**Tested something? Share it.** In FramePort open the game → **…** → **Share working config…** (it fills in the
recipe for you) or **Report a problem…** (attaches a diagnostics zip with personal data removed). Without the app:
[share a working config](https://github.com/spoopyghosty0/frameport/issues/new?template=working-config.yml) · [report a problem](https://github.com/spoopyghosty0/frameport/issues/new?template=bug-report.yml). Shared configs become built-in recipes for everyone.
## Built on
[OVRPort](https://github.com/Android-XR-Bridge/OVRPort) (Quest → OpenXR, originally
[ovrport/app](https://github.com/ovrport/app)) · Valve Lepton, Proton and SteamVR ·
[Revive](https://github.com/LibreVR/Revive) · Mesa (Zink) · [Khronos OpenXR SDK](https://github.com/KhronosGroup/OpenXR-SDK)
· Eclipse Temurin, Android apksigner and NDK · [Flet](https://flet.dev) · OculusDB and Steam store data.
What FramePort adds itself: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
## Documentation
| | |
|---|---|
| [INSTALL.md](docs/INSTALL.md) | Install, connect, update, PC VR, files, problem reports |
| [FRAME_SETUP.md](docs/FRAME_SETUP.md) | What setup changes on the Frame, networks and firewalls, undoing it |
| [COMPATIBILITY.md](docs/COMPATIBILITY.md) | What runs and how well |
| [GAMES.md](docs/GAMES.md) | Tested games and how well they run |
| [PLAYBOOK.md](docs/PLAYBOOK.md) | Symptoms and fixes per game |
| [FRAME_RUNTIME.md](docs/FRAME_RUNTIME.md) | Steam Frame runtime facts |
| [ARCHITECTURE.md](docs/ARCHITECTURE.md) | How the code is organised |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Code, recipes, translations |
## Development
See `CLAUDE.md` (architecture, commands, findings) and `docs/ARCHITECTURE.md`.
```
uv sync --extra dev
uv run frameport-gui # the app
uv run frameport --help # command line
uv run pytest # tests
```
## AI Usage Notice
While I would like to program everything manually, I no longer have much free time for personal projects. As a result I make use of AI tools to make it significantly quicker to debug compatibility issues.
## License
GPL-3.0-only (includes GPL-3.0 code from OVRPort). Not affiliated with Valve or Meta.
+8
View File
@@ -0,0 +1,8 @@
# Security
FramePort talks to your Steam Frame over SSH with its own key and runs a small agent there; it also downloads tools
and its own updates (checked against the release's SHA-256 sums and, on Windows, its signature).
To report a vulnerability, please open a GitHub security advisory for this repository (Security → Report a
vulnerability) instead of a public issue. Include the FramePort version (`frameport --version`) and how to reproduce
it. Fixes are released as normal updates; FramePort offers them automatically.
+29
View File
@@ -0,0 +1,29 @@
# Third-party notices
FramePort is GPL-3.0-only (see `LICENSE`). It includes or downloads the following third-party work.
## Included in this repository / the release bundles
| Component | Where | License |
|---|---|---|
| OVRPort VrApi → OpenXR adapter (`native/vrapi`, github.com/Android-XR-Bridge/OVRPort), with FramePort's changes | `native/vrapi-bridge/`, `artifacts/arm64-v8a/libvrapi.so` | GPL-3.0 (`native/vrapi-bridge/LICENSE.upstream`) |
| OVRPort platform compatibility library (`native/platform`) | `native/platformcompat/`, `artifacts/arm64-v8a/libovrplatformcompat.so` | GPL-3.0; Meta Platform SDK headers under the Meta Platform Technologies SDK License (`native/platformcompat/licenses/OCULUS-PLATFORM-SDK.txt`) |
| Khronos OpenXR SDK headers | used to build the native layers | Apache-2.0 / MIT (`native/vrapi-bridge/licenses/OPENXR-SDK.txt`) |
| Android NDK runtime (statically linked libc++) | native Android libraries | Apache-2.0 with LLVM exception, plus legacy notices (`native/vrapi-bridge/licenses/ANDROID-NDK.txt`) |
| Flet and Flutter (desktop app runtime) | release bundles | Apache-2.0 / BSD-3-Clause |
| flet-dropzone / desktop_drop (drag-and-drop) | release bundles | Apache-2.0 / MIT |
| FFmpeg 7.1.1 hardware HEVC wrapper (LGPL configuration, without GPL/nonfree components) | `artifacts/hevc/libstagefrighthw.so`; source/rebuild instructions in `native/hevc/build.py` and `native/hevc/README.md` | LGPL-2.1-or-later (`artifacts/hevc/COPYING.FFmpeg`); unmodified source: https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.xz |
| AOSP Android 11 native media/utility headers | `native/hevc/platform/` | Apache-2.0; copyright/license notices retained in the headers |
| Python packages (paramiko, zeroconf, psutil, pyelftools, capstone, UnityPy, PyYAML, requests, typer, pyaxmlparser, Pillow, cryptography, …) | release bundles | their own licenses (see each package's metadata) |
FramePort's own native code (the FrameBridge adapter, GL/Vulkan/OpenXR shims, the Windows helpers) is GPL-3.0-only.
## Downloaded at run time (not redistributed)
| Tool | Source | License |
|---|---|---|
| OVRPort / overport CLI | github.com/Android-XR-Bridge/OVRPort releases (fallback github.com/ovrport/app) | GPL-3.0 |
| Eclipse Temurin JRE | api.adoptium.net | GPL-2.0 with Classpath Exception |
| apksigner (Android build-tools) | dl.google.com Android repository | Apache-2.0 |
| Revive (portable copy, only if Revive isn't installed) | github.com/LibreVR/Revive releases | GPL-3.0 |
Valve's Lepton, Proton and SteamVR, and Meta's software, are used on your devices as installed by Steam / Meta;
FramePort doesn't distribute them.
+3948 -141
View File
File diff suppressed because it is too large. Load diff
+18 -6
View File
@@ -1,12 +1,24 @@
0f681f54b59cfad2efc8883aee5a0971c2fba09d9ba2dca15a136b0ac74a59b8 ./arm64-v8a/libfp_vk.so
8e00552d1ab90f82749db3caad4f773351fa8a28edcc5ea5cbd1b31c434ff32a ./arm64-v8a/libframe_xrshim.so
3dfcb0f2bec47857bcecc7261c58e076d872d4649718c40850f29e10c75477dd ./arm64-v8a/libglshim.so
dc62857b4f7a23b194060599339dfe72b38c16cdf4a9eb1b1f3b4d1fb9071a6d ./arm64-v8a/libopenxr_loader_generic.so
5becb96ee86fbda0ce98c0e0fd064f8ba092314aceaa400e3dcc785705dc3c23 ./arm64-v8a/libVkLayer_fp_shaderfix.so
e7554c6343ee2989b0a273ee6230e65c25bfe6499eefd00de19f5f0fee58754f ./arm64-v8a/libfp_langpack.so
321da502e0f8f46f0880aad39fe6b84bdef88f925164568814cf704a1b31a577 ./arm64-v8a/libfp_ovrp.so
40defdaddcda53bd2649eb48076fae1622bfc2bfc88e9e03c94fc8b45af2a4f2 ./arm64-v8a/libfp_ovrtrace.so
7522a7cfb236e48d3442d418c4820cd37760a9627c6bdef80fb0df82df5fd826 ./arm64-v8a/libfp_vk.so
383054f8b3b41dde76d062c71856cd3163655e50009c08454bc1793f393ead65 ./arm64-v8a/libfpg.so
5432674a59d02f411cd853a5dc57e3fa547d1ac518f25bf433fc54c43677177a ./arm64-v8a/libfpglmv.so
8a8f6b1da8952cb3933a5b53558424a5fc56043b2527a16bb6dd62a00d2de01a ./arm64-v8a/libframe_xrshim.so
fc559dbe0b87eecc3641256837293260cefb7c2ce7b21d808d10edd2a2dba9fc ./arm64-v8a/libglshim.so
1655921f4c91f2f336edf0aac66d8df1b2b649a272aafe365c1f2fa7867129de ./arm64-v8a/libopenxr_loader_generic.so
1feaeafad467c4cafdf2b018a4d84b0bee200c3f711697b4ce97e66a3ba256ca ./arm64-v8a/libovrplatformcompat.so
32525cd0a9ee3d9993d8871cd6905bdcf22cde4f4ba28f5db6434ce7d6554758 ./arm64-v8a/libvrapi.so
a79c598744b98b9bf581664a80bcee1a0d11a62fdcdb99f05a0f6f381b6498cd ./armeabi-v7a/libopenxr_loader_generic.so
aa4dc0020c77e12d41ef6ce80b23ad90c9cb7e882338eddf2261efe8645cf38d ./arm64-v8a/libvrapi.so
7943c6825e1c2841e54627f96acbd0754a3c06bb608c47f7aa15007aec2191a5 ./armeabi-v7a/libopenxr_loader_generic.so
1871eae093432d277da4bc751bf5f3269dfcf11f9168260b0c3caadb0dedb19d ./dex/oculusos-stubs.dex
b634ab5640e258563c536e658cad87080553df6f34f62269a21d554844e58bfe ./hevc/COPYING.FFmpeg
141de01f0d40b97d4f9a720db5ab8ea442f6aa35db5272048899292884994a1c ./hevc/libstagefrighthw.so
4516971bbb2b635e19b14d2d37b9353962876f7de02043e7457327052c1fcbc0 ./hevc/manifest.json
46c3dcad2c43cc30bea3b3680b362ed84a99c15d60714bbbbb422c80ecf90405 ./hevc/media_codecs_frameport.xml
529ea35d5d82474afe9e09ad1216d269317f56dd24a05fb100fced52b7b4dbca ./hevc/podman.py.txt
1aa733117cf57ccff7cf23f0425dbfd73b0332a3ef1c905ceeca0ccd0449c4e0 ./linux-arm64/XR_APILAYER_FRAMEPORT_timefix.json
28c2430a02bbd8902c5bfb9562c6fd0e318654f9e05c095bfeb94b0450ab1b07 ./linux-arm64/libxr_frameport_timefix.so
b10b3a5c10c3339fc63fd9f6cb4d01ea29be11a863d0ebad1389ea69fd471940 ./linux-arm64-bin/fp_venc
c2c70f4af1a5c3e6089dff1130161dd417f8044f99ec639eeecf1083930aab16 ./win-x64/fp_oculushmd.exe
60ebc5fea05b8945082e2ca8b9f2eb74616012a26eb50133af273dff0fcddc42 ./win-x64/fp_vrsettings.exe
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+502
View File
@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
Binary file not shown.
+19
View File
@@ -0,0 +1,19 @@
{
"revision": 8,
"runtime_sha256": "456e912c75cd389abcf6a63bc80e2a53bdc334371d00b200c93680388ae955e2",
"files": {
"libstagefrighthw.so": "141de01f0d40b97d4f9a720db5ab8ea442f6aa35db5272048899292884994a1c",
"podman.py": "529ea35d5d82474afe9e09ad1216d269317f56dd24a05fb100fced52b7b4dbca",
"media_codecs_frameport.xml": "46c3dcad2c43cc30bea3b3680b362ed84a99c15d60714bbbbb422c80ecf90405",
"COPYING.FFmpeg": "b634ab5640e258563c536e658cad87080553df6f34f62269a21d554844e58bfe"
},
"codecs": [
"video/hevc",
"video/avc",
"video/x-vnd.on2.vp9"
],
"build": {
"ndk_revision": "27.2.12479018",
"ffmpeg_source_sha256": "733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1"
}
}
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<MediaCodecs>
<Decoders>
<MediaCodec name="OMX.frameport.hevc.decoder" type="video/hevc" rank="64">
<Limit name="size" min="128x128" max="8192x8192" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-138240" />
<Limit name="blocks-per-second" range="1-7864320" />
<Limit name="bitrate" range="1-245000000" />
<Limit name="concurrent-instances" max="1" />
</MediaCodec>
<MediaCodec name="OMX.frameport.avc.decoder" type="video/avc" rank="64">
<Limit name="size" min="128x128" max="8192x8192" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-138240" />
<Limit name="blocks-per-second" range="1-7864320" />
<Limit name="bitrate" range="1-245000000" />
<Limit name="concurrent-instances" max="1" />
</MediaCodec>
<MediaCodec name="OMX.frameport.vp9.decoder" type="video/x-vnd.on2.vp9" rank="64">
<Limit name="size" min="128x128" max="4096x2304" />
<Limit name="alignment" value="2x2" />
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-36864" />
<Limit name="blocks-per-second" range="1-2211840" />
<Limit name="bitrate" range="1-245000000" />
<Limit name="concurrent-instances" max="1" />
</MediaCodec>
</Decoders>
</MediaCodecs>
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/python3
"""Add shared codecs to Lepton containers without editing their shared rootfs."""
import hashlib
import json
import os
import re
import shutil
import sys
from pathlib import Path
from xml.etree import ElementTree as ET
def mounts(directory, config, args):
if not args or args[0] != "run":
return []
name = None
for i, arg in enumerate(args):
if arg == "--name" and i + 1 < len(args):
name = args[i + 1]
elif arg.startswith("--name="):
name = arg.partition("=")[2]
if config.get("scope") == "shared":
# The common launcher supplies these values. Do not intercept arbitrary
# Podman containers or depend on a game's package/modified APK.
appid = os.environ.get("SteamAppId", "")
if not re.fullmatch(r"[0-9]+", appid) or name != f"lepton-steamlaunch-{appid}":
return []
app = Path(os.environ.get("STEAM_COMPAT_INSTALL_PATH", ""))
if app.name != "lepton-app" or not app.is_dir():
return []
root_arg = None
for i, arg in enumerate(args):
if arg == "--rootfs" and i + 1 < len(args):
root_arg = args[i + 1]
elif arg.startswith("--rootfs="):
root_arg = arg.partition("=")[2]
if not root_arg or not root_arg.endswith(":O"):
return []
root = Path(root_arg[:-2]).resolve()
else: # old per-game deployments remain compatible during migration
if name != f"lepton-steamlaunch-{config['appid']}":
return []
root = Path(config["lepton"]).resolve().parent / "images" / "rootfs"
expected_root = str(root) + ":O"
if not any(arg in (expected_root, "--rootfs=" + expected_root) for arg in args):
return []
device = Path("/dev/video-dec0")
runtime = root / "vendor/lib64/libstagefright_softomx.so"
upstream_plugin = (root / "vendor/lib64/libstagefrighthw.so").exists()
for i, arg in enumerate(args):
if arg == "--mount" and i + 1 < len(args):
fields = dict(item.split("=", 1) for item in args[i + 1].split(",") if "=" in item)
target = fields.get("destination", fields.get("target"))
if target == "/vendor/lib64/libstagefrighthw.so":
upstream_plugin = True
if target == "/vendor/lib64/libstagefright_softomx.so" and fields.get("source"):
runtime = Path(fields["source"])
if upstream_plugin:
print("FramePort video: using the runtime's hardware codec plugin", file=sys.stderr)
return []
if not device.exists() or hashlib.sha256(runtime.read_bytes()).hexdigest() != config["runtime_sha256"]:
print("FramePort video: device or runtime ABI differs; retaining the stock codecs", file=sys.stderr)
return []
xml = ET.parse(root / "vendor/etc/media_codecs.xml")
if not any(node.get("href") == "media_codecs_frameport.xml" for node in xml.getroot().findall("Include")):
ET.SubElement(xml.getroot(), "Include", href="media_codecs_frameport.xml")
# Immutable plugin versions can serve simultaneous app launches and
# different Lepton installations. Never share a temporary XML filename.
# The version directory stays as the agent verified it: the merged list goes to the user's runtime dir.
root_key = hashlib.sha256(str(root).encode()).hexdigest()[:16]
merged = merged_dir() / f"media_codecs.{root_key}.xml"
temporary = merged.with_suffix(f".{os.getpid()}.tmp")
xml.write(temporary, encoding="utf-8", xml_declaration=True)
temporary.replace(merged)
# Lepton supplies its own /dev tmpfs. A Podman --device node disappears
# beneath it; a bind mount matches Lepton's existing GPU/sound device setup.
result = ["--mount", f"type=bind,source={device},destination=/dev/video-dec0,rw"]
for path, target in (
(directory / "libstagefrighthw.so", "/vendor/lib64/libstagefrighthw.so"),
(merged, "/vendor/etc/media_codecs.xml"),
(directory / "media_codecs_frameport.xml", "/vendor/etc/media_codecs_frameport.xml"),
):
if not path.is_file():
raise FileNotFoundError(f"missing video codec mount: {path}")
result += ["--mount", f"type=bind,source={path},destination={target},ro"]
print("FramePort video: loading the Iris hardware codec plugin for this container", file=sys.stderr)
return result
def merged_dir():
runtime = os.environ.get("XDG_RUNTIME_DIR", "")
base = Path(runtime) if runtime and Path(runtime).is_dir() else Path.home() / ".cache"
path = base / "frameport-video"
path.mkdir(mode=0o700, parents=True, exist_ok=True)
return path
def switched_off(directory):
"""FRAMEPORT_NO_HW_VIDEO=1 (e.g. in a game's Steam launch options) or the Frame-wide switch (FramePort's
setting; the agent writes video-codec/disabled) leave every container with Android's stock codecs."""
if os.environ.get("FRAMEPORT_NO_HW_VIDEO", "") not in ("", "0"):
return True
return directory.parent.name == "versions" and (directory.parent.parent / "disabled").exists()
def real_podman(directory):
"""Find Podman independently of deployment.json, without recursing into this wrapper."""
own_bin = (directory / "bin").resolve()
own_script = Path(__file__).resolve()
# Lepton runs its `podman exec` calls (boot wait, app pid, logcat mirror) with the Android guest's PATH
# (/product/bin:/system/bin:...), which has no host Podman: the system folders come after PATH. Failing there
# broke Lepton's logcat mirror and app-pid checks, and the container was stopped early.
entries = os.environ.get("PATH", os.defpath).split(os.pathsep) + ["/usr/local/bin", "/usr/bin", "/bin"]
for entry in entries:
folder = Path(entry or os.curdir).resolve()
if folder == own_bin:
continue
found = shutil.which("podman", path=str(folder))
if found:
executable = Path(found).resolve()
if executable.parent != own_bin and executable != own_script:
return str(executable)
raise RuntimeError("no real Podman executable found outside the codec wrapper directory")
def main():
directory = Path(__file__).resolve().parent.parent
args = sys.argv[1:]
fallback = real_podman(directory)
if switched_off(directory):
os.execv(fallback, [fallback, *args])
try:
config = json.loads((directory / "deployment.json").read_text())
podman = Path(config.get("podman", fallback)).resolve()
if podman.parent == (directory / "bin").resolve() or podman == Path(__file__).resolve():
raise ValueError("configured Podman points to the codec wrapper")
extra = mounts(directory, config, args)
launch_args = [args[0], *extra, *args[1:]] if extra else args
os.execv(str(podman), [str(podman), *launch_args])
except Exception as exc: # a codec/configuration failure must never prevent the stock container from starting
print(f"FramePort video: retaining stock codecs: {exc}", file=sys.stderr)
os.execv(fallback, [fallback, *args])
if __name__ == "__main__":
main()
Binary file not shown.
+111 -36
View File
@@ -1,59 +1,134 @@
#!/usr/bin/env bash
# FramePort one-time Steam Frame setup. Run in the Frame's Desktop Mode terminal (Konsole):
# curl -fsSL http://<pc>:<port>/bootstrap.sh | bash
# FramePort one-time Steam Frame setup. Run in the Frame's desktop terminal (SteamVR dashboard -> Launch a program
# -> Desktop, then System -> Konsole):
# curl -fsS <pc-ip>:<port>/<code> | bash
# (the FramePort app shows the exact line and serves this script while its Setup page is open).
#
# What it does (asks before anything that needs sudo):
# 1. sets a password for the 'steamos' user if it has none (sudo needs one)
# 2. enables the SSH server (sshd)
# 3. authorizes the FramePort app's SSH key (no password needed afterwards)
# 4. announces this Frame on the local network (avahi service "_frameport._tcp") so the app finds it
# 5. checks for Valve's Lepton Android runtime and asks Steam to install it if missing
# What it does (no password, no sudo):
# 1. authorizes the FramePort app's SSH key (no password needed afterwards)
# 2. configures podman for Lepton (avoids a kernel keyring leak after ~200 game starts)
# 3. turns on Developer Mode if it's off (Valve's own helper; it also enables the SSH server and announces the
# Frame on the network as a SteamOS devkit). Steam restarts for that, which closes Desktop Mode: the rest
# runs on its own as a user service and the Frame returns to its normal view.
# 4. asks Steam to install Valve's Lepton Android runtime if it's missing, then tells the app it's done
# Log of the part that runs on its own: ~/.cache/frameport-setup.log
set -euo pipefail
PC_URL="__PC_URL__" # filled in by the app when serving the script
PAIR_CODE="__PAIR_CODE__"
say() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
DEVKIT_HELPER=/usr/bin/steamos-polkit-helpers/steamos-devkit-mode
STEAM_CONFIG=~/.local/share/Steam/config/config.vdf
JOB=~/.cache/frameport-setup.sh
LOG=~/.cache/frameport-setup.log
# Desktop Mode on SteamOS is a nested Plasma session inside steam.service, with its own XDG_RUNTIME_DIR and D-Bus:
# systemctl/systemd-run --user only reach the user's systemd through the real runtime dir.
user_systemd() {
XDG_RUNTIME_DIR="/run/user/$(id -u)" DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus" "$@"
}
say "FramePort setup for $(hostname) ($(. /etc/os-release; echo "$NAME $VERSION_ID"))"
if ! passwd -S "$USER" 2>/dev/null | grep -q ' P '; then
say "Your user has no password yet. SteamOS needs one for sudo (and as an SSH fallback)."
passwd
fi
say "Enabling the SSH server (sudo)"
sudo systemctl enable --now sshd
say "Authorizing the FramePort app's key"
key=$(curl -fsSL "$PC_URL/key?code=$PAIR_CODE")
key=$(curl -fsS "$PC_URL/key?code=$PAIR_CODE")
[[ "$key" == ssh-ed25519\ * ]] || { echo "Could not fetch the app's key from $PC_URL (is the app still open?)"; exit 1; }
mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
grep -qxF "$key" ~/.ssh/authorized_keys || echo "$key" >> ~/.ssh/authorized_keys
say "Announcing this Frame on the network (avahi)"
svc="<?xml version=\"1.0\" standalone='no'?>
<!DOCTYPE service-group SYSTEM \"avahi-service.dtd\">
<service-group>
<name replace-wildcards=\"yes\">FramePort on %h</name>
<service><type>_frameport._tcp</type><port>22</port><txt-record>user=$USER</txt-record><txt-record>pair=$PAIR_CODE</txt-record></service>
</service-group>"
echo "$svc" | sudo tee /etc/avahi/services/frameport.service >/dev/null || true
sudo systemctl enable --now avahi-daemon >/dev/null 2>&1 || true
sudo systemctl reload avahi-daemon >/dev/null 2>&1 || true
say "Configuring podman for Lepton"
# rootless podman leaks one kernel keyring per container start; ~200 game launches would exhaust the quota
mkdir -p ~/.config/containers
grep -qs '^ *keyring *=' ~/.config/containers/containers.conf || printf '[containers]\nkeyring = false\n' >> ~/.config/containers/containers.conf
say "Checking for Lepton (Valve's Android runtime)"
if ls ~/.local/share/Steam/steamapps/common/Lepton/lepton >/dev/null 2>&1; then
echo "Lepton found."
# The rest: Developer Mode (if needed), Lepton, telling the app. As a file, so it can run as its own user service:
# stopping Steam ends Desktop Mode and every program started in it, this terminal included.
mkdir -p ~/.cache
cat >"$JOB" <<'JOB'
set -u
MODE=$1 PC_URL=$2 PAIR_CODE=$3 CONFIG=$4 HELPER=$5
log() { echo "$(date +%T) $*"; }
if [[ $MODE == devmode ]]; then
sleep 5 # let the user read the terminal before Desktop Mode closes
# Steam re-applies "DevModeEnabled" from config.vdf at every start (calling Valve's helper) and rewrites
# config.vdf when it exits: stop Steam, set the value, run the helper (pkexec, allowed without a password), start.
log "stopping Steam"
systemctl --user stop steam.service
for _ in $(seq 40); do pgrep -x steam >/dev/null || break; sleep 1; done
if pgrep -x steam >/dev/null; then
log "Steam didn't stop"
systemctl --user start steam.service
exit 1
fi
cp "$CONFIG" "$CONFIG.before-frameport"
python3 - "$CONFIG" <<'PY'
import re, sys
path = sys.argv[1]
text = open(path, encoding="utf-8").read()
if re.search(r'"DevModeEnabled"\s+"\d+"', text):
text = re.sub(r'("DevModeEnabled"\s+)"\d+"', r'\1"1"', text)
else: # Steam keeps it in InstallConfigStore/developer
lines, keys, key, at = text.splitlines(keepends=True), [], None, None
for i, line in enumerate(lines):
s = line.strip()
if s == "{":
keys.append((key or "").lower())
if keys == ["installconfigstore", "developer"]:
at = ("in", i, line[:len(line) - len(line.lstrip())] + "\t")
break
elif s == "}":
if keys == ["installconfigstore"]: # end of the top section without a developer block
at = ("new", i, line[:len(line) - len(line.lstrip())] + "\t")
break
keys.pop()
elif re.fullmatch(r'"[^"]*"', s):
key = s.strip('"')
if at is None:
sys.exit("unexpected config.vdf layout")
kind, i, ind = at
if kind == "in":
lines.insert(i + 1, f'{ind}"DevModeEnabled"\t\t"1"\n')
else:
lines[i:i] = [f'{ind}"developer"\n', f"{ind}{{\n", f'{ind}\t"DevModeEnabled"\t\t"1"\n', f"{ind}}}\n"]
text = "".join(lines)
open(path, "w", encoding="utf-8").write(text)
PY
rc=$?
[[ $rc == 0 ]] && { "$HELPER" --enable; rc=$?; }
log "Developer Mode: $([[ $rc == 0 && -f /etc/steamos-devkit-enabled ]] && echo on || echo "failed ($rc)")"
systemctl --user start steam.service
[[ $rc == 0 ]] || exit 1
for _ in $(seq 90); do pgrep -x steam >/dev/null && break; sleep 1; done
sleep 20 # let Steam finish starting before asking it for anything
fi
if [[ -e ~/.local/share/Steam/steamapps/common/Lepton/lepton ]]; then
log "Lepton found"
else
echo "Lepton is missing. Make sure Developer Mode is on (Settings > System > Developer)."
echo "Asking Steam to install it now; confirm in Steam, or launch 'Lepton Development' from your library once."
(steam steam://install/3029110 >/dev/null 2>&1 &) || true
log "asking Steam to install Lepton (confirm it in Steam)"
steam steam://install/3029110 >/dev/null 2>&1 &
fi
if curl -fsS "$PC_URL/paired?code=$PAIR_CODE&user=$(id -un)&host=$(hostname)" >/dev/null; then
log "told FramePort: done"
else
log "couldn't reach FramePort at $PC_URL"
fi
JOB
if [[ -f /etc/steamos-devkit-enabled ]]; then
say "Developer Mode is on"
bash "$JOB" finish "$PC_URL" "$PAIR_CODE" "$STEAM_CONFIG" "$DEVKIT_HELPER" 2>&1 | tee "$LOG"
say "Done. Return to FramePort on your PC: this Frame should now appear as connected."
exit 0
fi
curl -fsS "$PC_URL/paired?code=$PAIR_CODE&user=$USER&host=$(hostname)" >/dev/null 2>&1 || true
say "Done. Return to FramePort on your PC: this Frame should now appear as connected."
say "Turning on Developer Mode"
if [[ ! -x "$DEVKIT_HELPER" || ! -f "$STEAM_CONFIG" ]] || \
! user_systemd systemd-run --user --collect --quiet --unit="frameport-setup-$$" \
bash -c 'bash "$0" "$@" >"$HOME/.cache/frameport-setup.log" 2>&1' \
"$JOB" devmode "$PC_URL" "$PAIR_CODE" "$STEAM_CONFIG" "$DEVKIT_HELPER"; then
echo "Couldn't turn it on automatically. Turn it on in Settings > System > Developer, then run this command again."
exit 1
fi
echo "Steam restarts to turn it on. That closes the desktop in a few seconds and the Frame returns to its"
echo "normal view; setup finishes on its own. If Steam asks to install Lepton, confirm it."
echo "Then return to FramePort on your PC: the Frame appears as connected within a minute."
@@ -6,10 +6,14 @@ notes: 'Native OpenXR GLES video player. 360 theatres/videos (equirect2 layers,
at 72 fps (the runtime asks for 4536 px per eye). Confirmed in the headset by the owner (2026-10-01). Its "Internal
Storage" list is /sdcard/4XPlayer: send videos with the game page''s "Add videos".'
details: 'Settings: equirect_emul (GLES worker draws 360 layers into a projection layer), stable_local, focus_hold,
scale 0.75; frame.swapchain_limit for its 7680x3840 theatre swapchains.'
scale 0.75; frame.swapchain_limit for its 7680x3840 theatre swapchains. Its hardware decoding mode (Java MediaCodec,
Vr4pMediaPlayer; its own FFmpeg is the software path) gets the Frame''s video hardware with frame.hw_video_decode
(added 2026-10-09, not yet checked in the headset).'
tested_version: 2.0.22
engine: Other
xr: OpenXR
frame:
- frame.hw_video_decode
adapter:
equirect_emul: 1
stable_local: 1
@@ -17,4 +21,6 @@ adapter:
scale: 0.75
verified:
date: '2026-10-01'
updated: '2026-10-10'
min_app: 0.12.1
source_hint: 4XVR Video Player
+21
View File
@@ -0,0 +1,21 @@
package: com.Aldin.WotW
title: 'Waltz of the Wizard: Extended Edition'
status: works
notes: From what I tested, it just works. My only complaint is that the haptics go pretty crazy. But I don't remember
what it was like when I played it in my Quest. So it could be fine. 100% playable.
tested_version: 5.0.8.1578
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-05'
known_good_sha256: 522cfebf954e1cab6054798479b0b32c5ba9e38cca83dd98db2ac0f7e3c0802a
app: 0.9.1
overport_cli: 1.2.5
frame_build: '20260922.6101926'
agent: 48
issue: 44
source_hint: WotW
@@ -0,0 +1,20 @@
package: com.Appnori.AllInOneSports
title: AllInOneSports
status: works
tested_version: 1.9.0
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
verified:
date: '2026-10-04'
known_good_sha256: a1f9535ac569068bba25f137f131db9d4c3e997c072f3e790beac8ffef701fe3
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 13
source_hint: All In One Sports
+28
View File
@@ -0,0 +1,28 @@
package: com.Armature.VR4
title: VR4
status: works
notes: Installs the no-ForceQuit build and fixes a campaign shader that hung the GPU after the opening cutscene.
details: Entering the campaign gave a black screen, slowing audio and a crash (Mercenaries loaded). One fragment shader
reads a loop counter before setting it, which hangs the GPU; the Vulkan shim zeroes it (vk_shader_fix). The
no-ForceQuit build is kept. Diagnosed and confirmed on a Frame by the reporter of GitHub issue 10.
tested_version: '2.3'
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
use_alt: true
adapter:
# one campaign shader reads an uninitialized loop counter and hangs the GPU (black screen, slowing audio, crash);
# the Vulkan shim inserts two OpStores that zero it and its accumulator (from the reporter's capture, GitHub
# issue 10)
vk_shader_fix: 6488:5dcd842db8d21e3fdd13ec916d2e34dd0cfdf12a92fffaf8a27115072ef55c59:2624:0x0003003e,138,18,0x0003003e,150,42
verified:
date: '2026-10-02'
known_good_sha256: 40ff74e37264b28ae8826923b69d0731d9620094c76462be34159643d6ae91b3
app: 0.3.4
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 26
issue: 1
updated: '2026-10-04'
source_hint: Resident Evil 4
@@ -0,0 +1,36 @@
package: com.CMGames.IntoTheRadius2
title: Into The Radius 2
status: works
notes: Plays well (owner-verified 2026-10-05). Space warp is off, the headset's brief focus losses are hidden
(focus_hold, up to 2.5 s), only Valve's foveation layer is loaded (its render-pass optimizer removed the fog) and
an invalid depth resolve in Unreal's render passes is dropped (vk_spec_fixes; it made models flicker and windows
show behind them). Needs FramePort 0.10.0 or newer. Loading a save can take over a minute.
details: Unreal Engine 5 game that uses Meta's Application SpaceWarp (extra motion-vector and depth swapchains). OVRPort's
patch_disable_space_warp doesn't reach Unreal Engine 5, so FrameBridge's hide_space_warp hides XR_FB_space_warp and
removes the space warp info from the eye images. Working config shared in GitHub issue 35. In the headset
(2026-10-05) the Frame dropped focus for 0.4 s and 1.0 s within ten seconds and Unreal paused each time; loading a save
shows no frames for 40-80 s while the game's Sentry SDK (debug mode) logs its breadcrumbs. Valve's VALVE_rpo
(render-pass optimizer) Vulkan layer removes the game's fog (owner-verified 2026-10-05; with only VALVE_fdm_injection
loaded the fog renders), which also hid the distance culling; ruled out for the remaining pop-in - Vulkan occlusion
query slots, Valve's FDM layer. The cause, found with Khronos' validation layer (vk_validation) - Unreal's render
passes use Qualcomm's shader resolve (VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM) together with a depth resolve
of a single-sampled depth attachment (VUID-VkSubpassDescription2-flags-04908, -03179), harmless on Quest's driver,
wrong depth on the Frame's Mesa; the Vulkan shim's vk_spec_fixes drops that resolve.
tested_version: 1.2.4
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
adapter:
equirect_emul: 1
hide_space_warp: 1
focus_hold: 1
focus_hold_ms: 2500
vk_spec_fixes: 1
lepton_env:
VK_INSTANCE_LAYERS: VK_LAYER_VALVE_fdm_injection
verified:
date: '2026-10-05'
issue: 35
min_app: 0.10.0
source_hint: Into The Radius 2
@@ -0,0 +1,19 @@
package: com.CortopiaStudios.Graves
title: GORN2
status: works
tested_version: 1.10.1
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-07'
known_good_sha256: d8a7949edc90c19902eb89f888ad6a350475387d630991767b3097667ad16d4c
app: 0.12.0
overport_cli: 1.2.5
issue: 88
source_hint: GORN 2
+19
View File
@@ -0,0 +1,19 @@
package: com.CyanWorlds.Myst
title: Myst
status: issues
notes: Minor graphical glitches on some objects.
details: The crash is in the Frame's SteamVR runtime (vrclient.so CVRInputLatest::UpdateActionStateInternal via
xrSyncActions) on the first input sync after focus, in 2 of 4 headset sessions. sync_guard serialises input syncs
with event polling and pauses them for 250 ms after focus returns (confirmed in the headset, no crash). The object
glitches are not application space warp (turning it off didn't change them and ran slightly worse).
tested_version: 3.3.0
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
adapter:
sync_guard: 1
verified:
date: '2026-10-04'
updated: '2026-10-04'
source_hint: Myst
+20
View File
@@ -0,0 +1,20 @@
package: com.CyanWorlds.Riven
title: Riven
status: works
notes: Plays as expected.
tested_version: 1.9.0
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
adapter:
equirect_emul: 1
verified:
date: '2026-10-04'
known_good_sha256: 7c211588f39c21d67998ac6a6aeb44a8ad66c6551a1b0feb1bcf44e2cef98bdf
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 26
source_hint: Riven
@@ -0,0 +1,24 @@
package: com.CyberneticWalrus.DoesitStackMeta
title: Does it Stack?
status: issues
notes: Mixed reality mode does not work (works on Demeo), everything else seems to be OK
tested_version: 1.02 (3683)
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
adapter:
haptic_fix: 1
refresh_rate: 90.0
verified:
date: '2026-10-09'
known_good_sha256: e9fce6ac812f1bb317a7a6959be89c5ff54e87f56af9ad4c42dff5fecad4efe8
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 112
source_hint: Does It Stack
@@ -0,0 +1,25 @@
package: com.FireproofStudios.TheRoomVR
title: The Room VR
status: works
notes: Plays normally (it used to stay on a grey screen).
details: Unity 2018.4 with built-in Oculus support. It started VR only with frame.unity_oculus_check, then Unity's
render thread crashed in the GL driver (Zink) when OVROverlay copied a 4x4 fade texture into its overlay layer;
frame.unity_no_overlay_copy skips that copy (the fade still works). frame.unity_runtime_msaa_off keeps the eye buffer
at one sample (also GitHub issue 38).
tested_version: '1.02'
engine: Unity
xr: VrApi
frame:
- frame.unity_no_msaa
- frame.unity_oculus_check
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_no_overlay_copy
device:
- device.text_input_window
verified:
date: '2026-10-05'
issue: 38
updated: '2026-10-05'
min_app: 0.11.0
source_hint: The Room VR
+20
View File
@@ -0,0 +1,20 @@
package: com.ForwardXP.nuke
title: Please Don't Touch Anything
status: works
notes: Seems functional
tested_version: '2.2'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-08'
known_good_sha256: 17460c8691b9ff82f6c7ca5597afd0aacf1a94aa30ebb6a6108802991b60f51b
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 106
source_hint: apks
@@ -0,0 +1,21 @@
package: com.FourPlayersStudio.Retronika
title: Retronika
status: works
tested_version: 3.2.601
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-07'
known_good_sha256: 290bfda3969547d5f1ff621ab5a8be9dd322fc9eee6b243c863576d4ff5b4b81
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 97
source_hint: Retronika
@@ -0,0 +1,21 @@
package: com.FunktronicLabs.TheLightBrigade
title: The Light Brigade
status: issues
notes: Judder in weapons
tested_version: '746'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-09'
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 114
source_hint: The Light Brigade
@@ -0,0 +1,16 @@
package: com.GhostlyBirdGames.BattleGlide
title: BattleGlide
status: works
notes: Freezes from the headset's brief focus losses are hidden (focus_hold).
details: The Frame drops the session out of focus for ~0.5 s every few seconds (11 times in 80 s of play) and Unreal
pauses each time; focus_hold hides dips up to 1 s once the game has been focused for 1 s. Longer dips (real
interruptions) still pause it.
tested_version: 0.4.1 (BETA)
engine: Unreal
xr: OpenXR
adapter:
focus_hold: 1
verified:
date: '2026-10-04'
updated: '2026-10-04'
source_hint: BattleGlide
@@ -0,0 +1,36 @@
package: com.ILMxLAB.VaderImmortal.ep1
title: 'Vader Immortal: Episode I'
status: works
notes: 'Plays (owner''s headset test): loading card, grip/trigger, hands and the lightspeed sequence fixed. Thumbs
follow the touches with frame.unreal_thumb_touch (Klownicle''s engine fix).'
details: Unreal Engine 4 (GLES). Found and verified in gameplay on a Frame by Klownicle (GitHub issue 49); FramePort
reimplements them as patches that match the game's code exactly and change nothing when it differs. The engine's
Quest checks (IsRunningOnSantaCruz) answer "not a Quest" on the Frame - the menu waited for a Quest-only shader
precompile that never starts (frame.unreal_quest_precompile makes the non-Quest branch report 100 %), and the
game's key map picked the empty Gear VR controls (frame.unreal_quest_keymap keeps the Quest set). Two lightspeed
shaders, as the Frame's GL driver (Zink) compiles them, read loop counters and accumulators before setting them
and hang the GPU; a Vulkan layer under Zink inserts the stores that zero them (frame.zink_shader_fix, zink_shader_fix;
the captured modules are from Lepton 2.8.14 and stop matching if a Frame update changes the driver's output -
the layer logs that). OVRPlugin asks for poses at its own clock (pose_time_fix). Unreal's Oculus input animates the
thumbs from near-touch, which the Frame never reports (frame.unreal_thumb_touch reads the touches instead; binding
the proximity to the touch inputs in FrameBridge didn't reach the game). The Frame's SteamVR runtime
leaks about 20 MB a second while the game runs (reported to Valve).
tested_version: 1.1.1+667256.cl.387770
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.unreal_quest_precompile
- frame.unreal_quest_keymap
- frame.unreal_thumb_touch
- frame.zink_shader_fix
adapter:
pose_time_fix: 1
zink_shader_fix: 12016:b2919629761ad268e0b21c72ac8520f81b76e72c3adc26897f97eae9a3e70a66:3092:0x0003003e,166,82,0x0003003e,177,82,0x0003003e,183,82,0x0003003e,189,82,0x0003003e,256,82,0x0003003e,266,82,0x0003003e,272,82,0x0003003e,278,82,0x0003003e,318,82,0x0003003e,328,82,0x0003003e,334,82,0x0003003e,340,82;11436:6f18be49f2aaa2452f962eb16f7af744c5c22a7b25f37ce681e0d6399e35a869:2932:0x0003003e,164,80,0x0003003e,175,80,0x0003003e,181,80,0x0003003e,187,80,0x0003003e,254,80,0x0003003e,264,80,0x0003003e,270,80,0x0003003e,276,80,0x0003003e,316,80,0x0003003e,326,80,0x0003003e,332,80,0x0003003e,338,80
verified:
date: '2026-10-09'
issue: 49
updated: '2026-10-09'
min_app: 0.12.1
source_hint: Vader Immortal- Episode I
@@ -0,0 +1,24 @@
package: com.ILMxLAB.VaderImmortal.ep2
title: 'Vader Immortal: Episode II'
status: works
notes: Plays (owner's headset test, 2026-10-09) with Episode I's fixes, which FramePort finds in this episode's
code too.
details: 'Unreal Engine 4 (GLES), the same engine build as Episode I: the Quest-only shader precompile and key map
(frame.unreal_quest_precompile, frame.unreal_quest_keymap), thumbs from the capacitive touches (frame.unreal_thumb_touch)
and poses at OVRPlugin''s clock (pose_time_fix). Episode I''s lightspeed shader fix doesn''t apply. The campaign
intro once stayed black with its dialogue playing; it rendered on the next run.'
tested_version: 2.0.3+667261.cl.387778
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.unreal_quest_precompile
- frame.unreal_quest_keymap
- frame.unreal_thumb_touch
adapter:
pose_time_fix: 1
verified:
date: '2026-10-09'
min_app: 0.12.1
source_hint: Vader Immortal- Episode II
@@ -0,0 +1,24 @@
package: com.ILMxLAB.VaderImmortal.ep3
title: 'Vader Immortal: Episode III'
status: works
notes: Plays (owner's headset test, 2026-10-09) with Episode I's fixes, which FramePort finds in this episode's
code too.
details: 'Unreal Engine 4 (GLES), the same engine build as Episode I: the Quest-only shader precompile and key map
(frame.unreal_quest_precompile, frame.unreal_quest_keymap), thumbs from the capacitive touches (frame.unreal_thumb_touch)
and poses at OVRPlugin''s clock (pose_time_fix). Episode I''s lightspeed shader fix doesn''t apply. The campaign
intro starts on a black screen with only dialogue: that is the game, not a bug.'
tested_version: 3.0.3+667263.cl.387932
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.unreal_quest_precompile
- frame.unreal_quest_keymap
- frame.unreal_thumb_touch
adapter:
pose_time_fix: 1
verified:
date: '2026-10-09'
min_app: 0.12.1
source_hint: Vader Immortal- Episode III
@@ -4,14 +4,25 @@ tested_version: '1.03'
source_hint: Sniper Elite VR
engine: Unity
xr: VrApi
status: unsupported
notes: 'GPU hang (zink: DEVICE LOST) even with MSAA off.'
details: Legacy VrApi via OVRPlugin.
status: works
notes: Plays with controllers that follow the hands (owner's headset test, Quest 1 build 35713).
details: 'Unity 2019.4 on its built-in Oculus VR (no Oculus XR Plugin). Its legacy frame loop never waited for frames
(GPU hang, zink: DEVICE LOST) and Unity reported only Go controllers: frame.unity_oculus_check. Its frame wait then
deadlocked at the Init scene (Unity skipped beginning a frame) and the physics-step pose update located the
controllers in the past (hands lagged): both fixed in that patch (revision 5), switched on for this game by ovrp_begin_gate and ovrp_hold_physics. Grabbing an object in the tutorial
vibrates the controller; OVRPort''s envelope conversion then allocated ~1 GB/s until the memory cap ended the game:
haptic_fix. The Quest 1 build has no arraysources_assets.hd, which the game loads on the Frame (it detects a Quest
2) and then skips the .sd bundle: textures are missing unless the .sd file is also present under the .hd name in the
game''s obb folder.'
frame:
- frame.unity_no_msaa
- frame.unity_oculus_check
adapter:
haptic_fix: 1
ovrp_begin_gate: 1
ovrp_hold_physics: 1
pcvr_alternative: Sniper Elite VR (Steam PC VR). Winter Warrior (Quest) works on the Frame.
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: e80883eb6945e267a375edf0ffd789268686440819add9d4dee9fdbdf466cbe4
date: '2026-10-07'
updated: '2026-10-07'
min_app: 0.12.1
@@ -0,0 +1,24 @@
package: com.MightyCoconut.WalkaboutMiniGolf
title: Walkabout Mini Golf
status: works
tested_version: '6.7'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
adapter:
controller_models: 1
haptic_fix: 1
scale: 1.5
verified:
date: '2026-10-08'
known_good_sha256: cf3b5cbe131af8a2baaa3f5c665b1c7001c8b299473abfcf98d90e3c02b08a2f
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 111
source_hint: Walkabout Mini Golf
@@ -0,0 +1,27 @@
package: com.NewFolderGames.IAmCat
title: I Am Cat
status: works
notes: Steady view with pose_consistency (the judder is gone).
details: Unity 2022.3 with the Oculus XR Plugin falls back to GLES (Zink) on the Frame, where its single-pass
(multiview) rendering drew the right eye wrong (GitHub issue 8); frame.unity_multipass renders each eye in its own
pass (OculusSettings.GetStereoRenderingMode + its inlined read in OculusLoader.Initialize). Poses and frame times
are consistent, but every frame reaches the runtime one display period late (two passes on Zink) and the game
clamps its physics step to 10 ms. The judder came from the game locating its views about three times per frame and
getting slightly different poses each time; FrameBridge pose_consistency returns the same views for repeated
queries of one display time (proposed in GitHub issue 8). The grey right eye on the loading screen is still open.
tested_version: 1.4.0.0
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.unity_multipass
device:
- device.text_input_window
adapter:
pose_consistency: 1
verified:
date: '2026-10-05'
issue: 8
updated: '2026-10-05'
min_app: 0.11.0
source_hint: I Am Cat
@@ -0,0 +1,21 @@
package: com.NewFolderGames.IAmMonkey
title: I Am Monkey
status: works
notes: Its intro video plays through FrameBridge's video panels.
details: The game plays its intro on a panel that an Android media player (ExoPlayer) draws into
(XR_KHR_android_surface_swapchain). The Frame's runtime lists that extension but refuses the call, so the panel had
no image and the game stayed black waiting for the video (GitHub issue 25). The adapter's surface_emul (on by
default) hands the player a real Android Surface and copies each video frame into an ordinary swapchain the panel
shows.
tested_version: 1.0.5
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-04'
issue: 25
updated: '2026-10-04'
source_hint: I Am Monkey
@@ -0,0 +1,29 @@
package: com.PixelToys.BattleSisters
title: BattleSisters
status: works
notes: Plays; controller buttons and vibration work, hands follow the controllers (pose_time_fix).
details: Unity 2019.4 with Unity's built-in Oculus support. frame.unity_oculus_check starts VR (Meta's system-app
check), adds the frame wait its legacy loop never makes (without it the GPU hung, black screen) and lets Unity's
Oculus input accept Lepton's device model (it only reported controllers on a device named "Oculus ...", so buttons
were dead). haptic_fix stops the first controller vibration from freezing the Frame (OVRPort's loader read its
duration in nanoseconds as seconds and the game ran out of memory). With pose_time_fix the hands follow the controllers
- OVRPlugin asked for hand poses at Android's monotonic "now", which on SteamOS 0.4.5 is 2.56 s behind the runtime's
XrTime, so the hands lagged far behind.
tested_version: 1.2.4
engine: Unity
xr: VrApi
frame:
- frame.unity_no_msaa
- frame.unity_oculus_check
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
adapter:
haptic_fix: 1
pose_time_fix: 1
verified:
date: '2026-10-08'
issue: 48
updated: '2026-10-08'
min_app: 0.12.1
source_hint: Battle Sister
@@ -0,0 +1,25 @@
package: com.StressLevelZero.BONELAB
title: BONELAB
status: works
notes: Builds 1.2068 and 1.2974 play (owner's headset tests). One recipe serves both builds - 1.2068 needs frame.unity_user_presence (head tracking and controls); 1.2974 also needs
frame.slz_vulkan_hooks (72 fps after about 35 s of shader prewarming), which changes nothing on 1.2068.
details: Both builds - the game runs (72 fps), but its player body stayed frozen - no head tracking, the controllers stuck to the
model, no buttons - although OpenXR input and OVRPlugin's poses were fine. A few seconds after start (when Unity
switches XR loaders) OVRPlugin reports the worn headset as not worn (ovrp_GetUserPresent2 -> 0), and BONELAB's
Marrow rig only follows the player while Unity's HMD device reports UserPresence (OpenControllerRig checks
XRHMD.IsUserPresent every frame). frame.unity_user_presence reports the headset as worn. Build 1.2974 only - it adds Stress
Level Zero's graphics plugin (libSLZQuestNative.so), which hooks Unity's Vulkan start-up (vkCreateInstance/
vkCreateDevice) and vkCreateSampler; on the Frame its vkCreateInstance wrapper calls an invalid pointer right after
OVRPlugin's pre-init instance is destroyed (a jump to 0, into an unloaded library, or a hang). frame.slz_vulkan_hooks
switches its two registrations off, so Unity starts Vulkan itself; the plugin's pipeline cache isn't used.
tested_version: 1.2974.57485
engine: Unity
xr: OpenXR
frame:
- frame.unity_user_presence
- frame.slz_vulkan_hooks
verified:
date: '2026-10-08'
updated: '2026-10-08'
source_hint: BONELAB
min_app: 0.12.1
+22
View File
@@ -0,0 +1,22 @@
package: com.ToastVR.Matilda
title: Max Mustard
status: works
tested_version: 1.1.0
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-08'
known_good_sha256: 9a67459fa36c3b9ac0d035e6c43b1809b39772699333e8cfd7d2a4d7f17926a7
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 110
updated: '2026-10-09'
source_hint: com.ToastVR.Matilda
@@ -0,0 +1,22 @@
package: com.ToastVR.RichiesPlankExperience
title: Richie's Plank Experience
status: works
tested_version: 2.3.585
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-07'
known_good_sha256: 7eb1366c2398e554624a5d66aefb0c731c64b1b6944bc1726d9187f123c37fb7
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20260922.6101926'
agent: 59
issue: 95
source_hint: apks
+3
View File
@@ -9,8 +9,11 @@ notes: Some launch warning text is still upside down; the rest of the UI is fixe
may not work.
details: Ubisoft online login may not work. Data folder holds raw assets (start0..2, .climb, bundles), not .obb
files; install to obb as-is.
overport_extra:
- patch_ac_nexus_no_appsw_90
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: 89644a12bf8df956fa3d3a9a40540ba9e1fb62f63494714a05c9f05984383ac8
no_appsw_90: '2026-10-02, OVRPort 1.2.5 (owner: 90 Hz felt better than 72 Hz; same known issues)'
@@ -0,0 +1,23 @@
package: com.VR_HOT.VR_HOT_Quest
title: VR HOT Quest
status: works
tested_version: 0.8.8.1
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
adapter:
controller_models: 1
haptic_fix: 1
verified:
date: '2026-10-08'
known_good_sha256: c321606c536eba1673572a9f44fd9e20d2cb5bd9609d536189e6ad7057b9cd67
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20260922.6101926'
agent: 59
issue: 98
source_hint: VR-HOT-Quest-0.8.8.1
@@ -0,0 +1,22 @@
package: com.Warpfrog.BladeAndSorcery
title: 'Blade & Sorcery: Nomad'
status: works
notes: The headset's brief focus losses are hidden (focus_hold, up to 2.5 s).
details: The Frame's runtime drops focus now and then (mostly 1.5-7 s, some only milliseconds); the game pauses
("System menu opened", the world freezes) and re-aligns the player when focus returns (Player.OnVRPresence ->
Teleport, the sideways jump). They match the headset's wear sensor flickering off while worn (SteamVR "HMD off" 0.5-2
s), which only this game reacts to; focus_hold hides dips up to 2.5 s here. Rendering keeps 72 fps throughout.
tested_version: 1.3.1
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
focus_hold: 1
focus_hold_ms: 2500
verified:
date: '2026-10-04'
updated: '2026-10-04'
source_hint: Blade & Sorcery Nomad
+12 -5
View File
@@ -1,16 +1,23 @@
package: com.YourCompany.RoboRecall
title: Robo Recall
tested_version: '1.0'
source_hint: 'Robo Recall- Unplugged'
engine: Unreal
xr: VrApi
status: works
notes: Needed the LAUNCHER category fix.
details: Source APK is a community 'patch+savefix+90Hz' build.
details: Source APK is a community 'patch+savefix+90Hz' build. Shares Vader Immortal's Unreal 4 Oculus input (GitHub
49) - thumbs follow the touches (frame.unreal_thumb_touch) and controller poses are located at the right time
(pose_time_fix); added 2026-10-09 from Vader's headset results, not yet checked in this game.
tested_version: '1.0'
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.unreal_thumb_touch
adapter:
pose_time_fix: 1
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: 4ce6e3563da131e288645f4b62a634ac98043e55bc42b7c0ad5f461207d5f53c
updated: '2026-10-09'
source_hint: Robo Recall- Unplugged
+25
View File
@@ -0,0 +1,25 @@
package: com.YourCompany.SWP_VR
title: Star Wars Pinball VR
tested_version: '1.4'
source_hint: Star Wars Pinball VR
engine: Unreal
xr: VrApi
status: works
notes: Plays (owner's headset test); one short audio hiccup seen.
details: 'Unreal 4.25 (GLES) built against OVRPlugin 1.44. Four Frame problems in a row: Zink crashed on Unreal''s
multisampled render-to-texture (fault addr 0x10000 on the RHIThread): frame.unreal_gl_shim, which keeps Unreal''s
multiview and draws those passes single-sampled; OVRPort''s OVRPlugin lacks ovrp_GetPTWNear, so Unreal''s Oculus
module never started VR (then a null pointer in GetMultiViewSceneColor): frame.unreal_ovrp_entrypoints; the engine''s
OpenSSL assembly has unpaired return-address checks the Frame''s CPU enforces (SIGILL on the HttpManager thread):
frame.pac_hints. Needs its OBB (main.10765).'
frame:
- frame.unreal_gl_shim
- frame.unreal_ovrp_entrypoints
- frame.pac_hints
adapter:
haptic_fix: 1
verified:
date: '2026-10-08'
issue: 83
updated: '2026-10-08'
min_app: 0.12.1
+23
View File
@@ -0,0 +1,23 @@
package: com.asg.clockworkdev
title: Clockwork
status: works
tested_version: '1.29'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-09'
known_good_sha256: 99a14eed320ba267153963c2d87d4e11e943b9920d48dfd5352c681de28ba95e
app: 0.12.1.dev203
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 67
issue: 116
source_hint: com.asg.clockworkdev
@@ -0,0 +1,23 @@
package: com.beatgames.beatpaber
title: Beat Saber (co-existence build)
status: works
notes: A Beat Saber build with its own package name, so a modded and an unmodded Beat Saber can be installed side by
side.
details: The submitted build's app label was very long and the game didn't appear in the Frame's Steam library (GitHub
issue 27, a shortcut Steam dropped again; fixed in 0.7.0); the recipe's title names it.
tested_version: 1.45.1_27839
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-05'
known_good_sha256: 9965b01d5d1a3707bce1762f60d5419ce3e89bc095c63586f6940bb69696e9fd
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 29
source_hint: Beat Saber
@@ -0,0 +1,21 @@
package: com.beatgames.beatsaber.lj369vr
title: Beat Saber
status: works
tested_version: 1.40.8_7379
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
device:
- device.text_input_window
verified:
date: '2026-10-06'
known_good_sha256: 6366a5411328b21de9e2da034af78290882b3c27b7a8f0c61688196e91320055
app: 0.11.0
overport_cli: 1.2.5
frame_build: '20261005.6135832'
agent: 56
issue: 68
source_hint: Beat Saber
@@ -0,0 +1,19 @@
package: com.beatgames.beatsaber
title: Beat Saber
status: works
tested_version: 1.40.8_7379
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-03'
known_good_sha256: ee720e040931f2547f7611e58ec5ad72d86e800dd4cf3135f576019683f2f359
app: 0.6.1
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 33
issue: 6
source_hint: Beat Saber
+15 -5
View File
@@ -1,16 +1,26 @@
package: com.camouflaj.manta
title: 'Batman: Arkham Shadow'
tested_version: 1.4.1-350961
source_hint: 'Batman- Arkham Shadow'
engine: Unity
xr: OpenXR
status: works
notes: Large data set (~27 GiB) incl. all language packs.
details: Uses Meta XR Audio (Wwise), handled by patch_meta_xr_audio. Includes all language packs (~28 GB).
details: 'Uses Meta XR Audio (Wwise), handled by patch_meta_xr_audio. Cutscenes are 8K HEVC panoramas: frame.hw_video_decode
decodes them on the Frame''s hardware, adapter.surface_native shows them in stereo (PRs #96, #128). Includes all
language packs (~28 GB). sync_guard (to test, GitHub #102) - a reporter''s game quit to Steam''s waiting screen
after the Frame runtime crashed in xrSyncActions (CVRInputLatest::UpdateActionState), the input race Myst had.'
tested_version: 1.4.1-350961
engine: Unity
xr: OpenXR
overport_extra:
- patch_disable_space_warp
frame:
- frame.hw_video_decode
adapter:
sync_guard: 1
surface_native: 1
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: 796d1cab08f614d72c50d9702974c719c0908f5de91183cfe02d1fd5eb09551a
updated: '2026-10-10'
min_app: 0.12.1
source_hint: Batman- Arkham Shadow
+17
View File
@@ -0,0 +1,17 @@
package: com.camouflaj.salmon
title: Marvel's Iron Man VR
status: works
tested_version: 0.1.0-250068
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-05'
known_good_sha256: 41e0ab90f622afd50accb0b6e2553520d30a6cc82e5ab4cbb2341b48f7316a71
app: 0.9.1
overport_cli: 1.2.5
issue: 47
source_hint: Marvel's Iron Man VR
@@ -0,0 +1,21 @@
package: com.characterBank.ruinsmagus
title: RUINSMAGUS
status: works
tested_version: 1.2.3
engine: Unity
xr: VrApi
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-07'
known_good_sha256: 230e5625fbdfebb47c4d96aeb87f45270e4e6c79a33c08315c90626ab7465fe5
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 89
source_hint: RUINSMAGUS
@@ -0,0 +1,22 @@
package: com.cloudheadgames.pistolwhip
title: Pistol Whip
status: works
notes: 120 HZ
tested_version: 1.6.0.2
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-08'
known_good_sha256: ebd97af54c59d59d473c98492c1bb26ce6059b7e59f27a08acfc5ada23d0b774
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 100
source_hint: Pistol Whip
+25
View File
@@ -0,0 +1,25 @@
package: com.coatsink.alone
title: Jurassic World Aftermath Collection
status: works
notes: Plays (owner's headset test, 2026-10-06).
tested_version: v3.16
engine: Unity
xr: VrApi
frame:
- frame.unity_no_msaa
- frame.unity_oculus_check
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
- frame.vrapi_stub
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-06'
known_good_sha256: 0566b39d96258fa15eb1b03f27a7ad4219eb5442b0355cd803ed1cf13313f1b3
app: 0.12.0
updated: '2026-10-06'
min_app: 0.12.0
source_hint: Jurassic World Aftermath Collection
@@ -0,0 +1,18 @@
package: com.crowscrowscrows.AccountingPlus
title: Accounting+
status: works
notes: Plays normally, including the "press any button" screen after choosing to sit or stand.
details: Unity 2017.4 built-in Oculus support. frame.unity_oculus_check gets VR started (Meta's system-app check and
the frame wait its legacy loop never makes, libfp_ovrp.so), ~72 fps. The motion warning after the stance selection
waits for a mouse click (Input.GetMouseButtonDown), which a Quest delivers for the controller press and Lepton never
does; the same library now counts a newly pressed trigger or A/B/X/Y as that click.
tested_version: 1.24.35
engine: Unity
xr: VrApi
frame:
- frame.unity_oculus_check
verified:
date: '2026-10-06'
updated: '2026-10-06'
min_app: 0.11.0
source_hint: Accounting+
+22
View File
@@ -0,0 +1,22 @@
package: com.curif.AgeOfJoy
title: AgeOfJoy
status: works
tested_version: '1.0'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.oculusos
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-08'
known_good_sha256: 9780e71e417b86290147c67c83755305801d8957909734c717a519034edefdf9
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 103
source_hint: AgeOfJoy 05 rc30
+23
View File
@@ -0,0 +1,23 @@
package: com.drbeef.doom3quest
title: Doom3Quest
status: issues
notes: 'HUD and PDA show with frame.gl_multiview_fbo (Xandrix1987''s headset test, GitHub 77, no frame-rate drop
with the PDA open). Open: the player sometimes switches between walking and running.'
details: Doom3Quest compiles every vertex shader for two views (OVR_multiview) and draws its HUD/PDA into single-view
framebuffers. Mesa (the Frame's GL) rejects that combination as the spec requires and drops the draw, so they
stayed black; frame.gl_multiview_fbo draws those passes with a single-view copy of the shader. Xandrix1987's framebuffer.cpp
fix went upstream as a PR to Team-Beef-Studios/Doom3Quest.
tested_version: 1.4.8
engine: Other
xr: OpenXR
frame:
- frame.gl_multiview_fbo
verified:
date: '2026-10-06'
known_good_sha256: 3c733f5cd08b6fa5d9e2775b1c1aee36b5943518b5d8451ba87e3c59a702afdf
app: 0.12.0
overport_cli: 1.2.3
issue: 77
updated: '2026-10-09'
min_app: 0.12.1
source_hint: doom3quest148
+17
View File
@@ -0,0 +1,17 @@
package: com.drbeef.lambda1vr
title: Lambda1VR
status: works
notes: 'Needs the game data: upload the release''s xash folder to the game''s storage (Files tab) and set --msaa
1 in xash/commandline.txt. Owner''s headset test, 2026-10-06.'
tested_version: 1.7.3
engine: Other
xr: OpenXR
frame:
- frame.tbxr_vendor
verified:
date: '2026-10-06'
known_good_sha256: 10bbccceb8d9a84ff3bcc9a21fd59db52784ff7742998bbe5b30d938dd7b97d2
app: 0.12.0
updated: '2026-10-06'
min_app: 0.12.0
source_hint: Lambda1VR
@@ -0,0 +1,18 @@
package: com.enhanceexperience.tetriseffect
title: TetrisEffect
status: works
notes: Opened the game, messed around with the menu, and played the first level. Works great.
tested_version: 2.0.2
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
verified:
date: '2026-10-05'
known_good_sha256: 9ea10027ad8b7aefba8c14f23575c9cbbcaf3b38d12b971ea9c06635721b23c1
app: 0.9.1
overport_cli: 1.2.5
frame_build: '20260922.6101926'
agent: 48
issue: 45
source_hint: tetriseffect
+11 -5
View File
@@ -1,18 +1,24 @@
package: com.forcefieldxr.timestall
title: Time Stall
tested_version: '1.0'
source_hint: Time Stall
engine: Unreal
xr: VrApi
status: issues
notes: Both eyes distort during movement (unresolved).
details: Legacy VrApi via OVRPlugin.
details: Legacy VrApi via OVRPlugin. Shares Vader Immortal's Unreal 4 Oculus input (GitHub 49) - thumbs follow the
touches (frame.unreal_thumb_touch) and controller poses are located at the right time (pose_time_fix); added 2026-10-09
from Vader's headset results, not yet checked in this game.
tested_version: '1.0'
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.unreal_thumb_touch
- frame.nodebug
adapter:
pose_time_fix: 1
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: 50c4d05b663b2f1851f5a7d650a89fd34587d65fafba13cc58671c96f7016db6
updated: '2026-10-09'
source_hint: Time Stall
+24
View File
@@ -0,0 +1,24 @@
package: com.harmonixmusic.kata
title: Audica
status: works
tested_version: 1.0.3.4
engine: Unity
xr: VrApi
frame:
- frame.unity_no_msaa
- frame.unity_oculus_check
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-09'
known_good_sha256: bc2c00fe049fd97643a296e622e3a90e08f0bd796ee454b0278525e9d72f8139
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 126
@@ -0,0 +1,20 @@
package: com.iillusions.spacepiratetrainerquest
title: Space Pirate Trainer Quest
status: works
tested_version: '1.97'
engine: Unity
xr: VrApi
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
device:
- device.text_input_window
verified:
date: '2026-10-04'
known_good_sha256: 711d87e6c1fa14fdcdc8bab5792657523d0281b5d904f7f1abafd98f3189d2c0
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 14
source_hint: Space Pirate Trainer
+27
View File
@@ -0,0 +1,27 @@
package: com.ilmxlab.tales
title: 'Star Wars: Tales from the Galaxy''s Edge'
status: unknown
notes: Not working yet - after the intro logos and a loading animation the picture goes black (GitHub issue 61).
Gets the controller fixes found for Vader Immortal (same studio) to test.
details: Unreal Engine 4 (GLES) by ILMxLAB, like Vader Immortal, but a different engine build - it has none of Vader's
Quest-only branches (no GetQuestShaderPrecompilePercent or RPOC key map; it precompiles shaders through Unreal's
own pipeline cache), so frame.unreal_quest_precompile/_keymap don't apply. Its seasons and Wwise banks are Meta
platform asset files (frame.asset_files). Vader's OVRPlugin findings apply to it as well - poses asked for at
OVRPlugin's own clock (pose_time_fix) and thumbs from near-touch, which the Frame never reports (frame.unreal_thumb_touch).
Ruled out for the black picture so far (see the diagnostics in issue 61) - asset-file paks, Valve's foveation,
GL errors; the game's own eye image reads back black.
tested_version: 1.1.9+734762.cl.439699
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
frame:
- frame.asset_files
- frame.unreal_thumb_touch
adapter:
pose_time_fix: 1
verified:
issue: 61
updated: '2026-10-09'
min_app: 0.12.1
source_hint: Star Wars- Tales from the Galaxys Edge
+19
View File
@@ -0,0 +1,19 @@
package: com.lakento.dinosquest
title: Dinosaur Island
status: works
tested_version: 1.7.5
engine: Unity
xr: VrApi
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-03'
known_good_sha256: 41ecbc728dc533eebcc3980e140fe1764fbd1958735d8a299c63fa9cda13a923
app: 0.6.2
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 33
issue: 12
source_hint: DINOSAUR ISLAND
@@ -0,0 +1,24 @@
package: com.markschramm.gravitylab
title: Gravity Lab
status: works
notes: Works great, along with passthrough mode
tested_version: '1.221'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
- frame.unity_gl_shim
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-09'
known_good_sha256: 82c95ee7487a130b6e37b967dd97c8362bf4d7e873fcff823f2c7877a62ff99f
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 113
source_hint: Gravity Lab
+12 -5
View File
@@ -1,18 +1,25 @@
package: com.nDreams.PhantomQuest
title: 'Phantom: Covert Ops'
tested_version: '1.2'
source_hint: 'Phantom- Covert Ops'
engine: Unreal
xr: VrApi
status: issues
notes: DLC/store button crashes (no Meta store). Installs the no-ForceQuit build.
details: The regular build quits itself on the Frame (System.exit after a failed platform check), so the no-ForceQuit
build is installed.
build is installed. Shares Vader Immortal's Unreal 4 Oculus input (GitHub 49) - thumbs follow the touches (frame.unreal_thumb_touch)
and controller poses are located at the right time (pose_time_fix); added 2026-10-09 from Vader's headset results,
not yet checked in this game.
tested_version: '1.2'
engine: Unreal
xr: VrApi
alt_overport:
- patch_remove_unreal_force_quit
use_alt: true
frame:
- frame.unreal_thumb_touch
adapter:
pose_time_fix: 1
verified:
date: '2026-09-28'
overport_cli: 1.2.3
overport_runtime: 3.4.3-23204ea
known_good_sha256: bb02b20a23fbe5e7a580ecde15a3cd015a4183421a51aab4a4dbcddbe7a09d1d
updated: '2026-10-09'
source_hint: Phantom- Covert Ops
+19
View File
@@ -0,0 +1,19 @@
package: com.odders.shapeit
title: BodyCombat
status: works
tested_version: 3.0.0
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-05'
known_good_sha256: 1aa5b2a46b25c86db65e3355a575af14b5d4d89b967c812274f181aab2e62b33
app: 0.9.1
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 48
issue: 56
source_hint: LES MILLS BODYCOMBAT
@@ -0,0 +1,19 @@
package: com.owlchemylabs.jobsimulator
title: Job Simulator
status: works
tested_version: 1.4.0.6515
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-03'
known_good_sha256: 64638d7f93bb93cc61f422a43a08bb0d35b9bb4b463e90a42da7002147f03d1b
app: 0.6.2
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 33
issue: 11
source_hint: Job Simulator
+20
View File
@@ -0,0 +1,20 @@
package: com.parkline.wander
title: Wander
status: works
tested_version: '0.3569'
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
device:
- device.text_input_window
verified:
date: '2026-10-04'
known_good_sha256: c0c9de22b3646f35009a53796757d26f8d4e95259713f26a18fae2be995b23aa
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 17
source_hint: Wander
+25
View File
@@ -0,0 +1,25 @@
package: com.playful.LuckysTale
title: Lucky's Tale
status: works
notes: Plays normally; touching a save slot no longer freezes the Frame (haptic_fix).
details: Touching a save slot vibrates the controller through XR_FB_haptic_amplitude_envelope; OVRPort's OpenXR
loader converts that envelope with the duration in nanoseconds read as seconds and allocates an enormous buffer, so
the Frame ran out of memory and froze (found by the GitHub issue 9 reporter). FrameBridge's extension shim turns the
envelope into a plain vibration before OVRPort's loader sees it (haptic_fix). Brief pauses came from the headset's
wear sensor flickering, now hidden by focus_hold (on by default).
tested_version: 1.0.55
engine: Unity
xr: VrApi
frame:
- frame.unity_text_input
- frame.unity_runtime_msaa_off
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-05'
issue: 9
updated: '2026-10-05'
min_app: 0.11.0
source_hint: Luckys Tale
+28
View File
@@ -0,0 +1,28 @@
package: com.qcxr.qcxr
title: QuestCraft
status: works
notes: Minecraft runs in VR (Vivecraft, about 72 fps; drops while worlds load). Needs FramePort 0.10.0 or newer for
the picture (older versions show black). On first start QuestCraft downloads its Java runtime, which didn't unpack on
the Frame once (see details).
details: QuestCraft downloads its Java runtime (JRE.zip from QuestCraft's GitHub releases) into files/runtimes/JRE
on first start; on the Frame that step once left nothing behind ("libjvm.so not found"; unpacked by hand). Two
Frame fixes, both owner-verified 2026-10-05. (1) Minecraft 1.21.5 checks GL errors strictly and aborted with
"OpenGL error 1282", an error the Frame's Mesa (Zink) reports where Quest's driver doesn't; QuestCraft's GL-to-GLES
layer (LTW) ignores GL errors when LIBGL_NOERROR is set, which Lepton passes from LEPTON_ENV_LIBGL_NOERROR. (2) LTW
passes desktop GL_DEPTH_COMPONENT32 through, which Mesa rejects, so every framebuffer was incomplete and the picture
black; frame.ltw_depth (automatic for APKs with libltw.so) loads GLES through a shim that asks for
GL_DEPTH_COMPONENT32F. Left over, harmless so far - Mesa still reports about 4 GL_INVALID_OPERATION per frame
("in glthread", so the call is unknown; mesa_glthread=false would name it).
tested_version: 6.0.0-RC4
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
lepton_env:
LEPTON_ENV_LIBGL_NOERROR: '1'
verified:
date: '2026-10-05'
updated: '2026-10-05'
source_hint: QuestCraft
@@ -0,0 +1,20 @@
package: com.resolutiongames.abvriop.santacruz
title: palazzo_santacruz
status: works
notes: Played a few levels. Passthrough also works.
tested_version: 3.7.6.10866-release
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-05'
known_good_sha256: 394214a68297c1e5b019dc4f65b145e7bd0e98604205616364e0c151c1afd894
app: 0.9.1
overport_cli: 1.2.5
frame_build: '20260922.6101926'
agent: 48
issue: 46
source_hint: abvriop
@@ -0,0 +1,19 @@
package: com.resolutiongames.cookinggame
title: Cook-Out
status: works
tested_version: 1.20.0.10625-release
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-03'
known_good_sha256: 7217649c503adf76f3a959fc72858c446c2a42a9ce9e209286977b1950397915
app: 0.6.1
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 33
issue: 3
source_hint: com.resolutiongames.cookinggame
+14
View File
@@ -0,0 +1,14 @@
package: com.roblox.client
title: Roblox
status: unsupported
notes: Crashes on its first VR frame on the Frame.
details: SIGSEGV on Roblox's render thread right after it re-creates its eye swapchains (format 37, which the Frame
doesn't offer, retried as sRGB 43) — in its own code or inside the runtime's xrBeginFrame. No integrity or login
check involved; also needs an online login once it runs.
tested_version: 2.741.1051
engine: Other
xr: OpenXR
verified:
date: '2026-10-04'
updated: '2026-10-04'
source_hint: Roblox
@@ -0,0 +1,19 @@
package: com.steelcrategames.keeptalkingandnobodyexplodes
title: Keep Talking and Nobody Explodes
status: works
tested_version: 1.10.15
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-04'
known_good_sha256: 1a6f18e6d7b077e2662c7e633d473018067f4c871f5c45c4632c58233feaeac5
app: 0.6.3
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 35
issue: 15
source_hint: Keep Talking and Nobody Explodes
+21
View File
@@ -0,0 +1,21 @@
package: com.stremio.vrone
title: Stremio
status: works
notes: 'Unity 6 VR media centre (its interface is web pages in Vuplex 3D WebView). Text fields closed at once on the
Frame (no system keyboard): frame.unity_text_input keeps them selected and device.text_input_window shows the
Android window so Steam''s on-screen keyboard (or Type on Frame from the PC) types into them; confirmed in the
headset by the owner (2026-10-03), who confirmed it working. Note: the add-ons page can stay blank in VR (the
add-on sync itself succeeds). "Play in an external player" can''t reach another app: Lepton sends every link to
Steam''s browser.'
details: 'Patches: frame.unity_text_input (TMP_InputField.TouchScreenKeyboardShouldBeUsed -> false,
isKeyboardUsingEvents -> true; uGUI InputField too), device.text_input_window (lepton-show-flatscreen).'
tested_version: 0.7.5
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
verified:
date: '2026-10-03'
source_hint: Stremio
+17
View File
@@ -0,0 +1,17 @@
package: com.survios.Creed
title: Creed
status: works
tested_version: CRU-386950
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
verified:
date: '2026-10-05'
known_good_sha256: c319dd95198a0a96a883aa70f6be9c843da0a265967fa4a7343ce7e6f4bfdc87
app: 0.10.0
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 54
issue: 60
source_hint: Creed Rise to Glory
+22
View File
@@ -0,0 +1,22 @@
package: com.tvb.cubism
title: cubism
status: works
tested_version: 1.8.0
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
scale: 2.0
verified:
date: '2026-10-09'
known_good_sha256: e4e000392e53111a991c1c78653c9241b8007f81dcdb126a4f4b2003033f5a6e
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 59
issue: 121
source_hint: com.tvb.cubism
@@ -0,0 +1,26 @@
package: com.vertigogames.ImpactDevelopment
title: Metro Awakening
status: works
notes: Plays (owner's headset test) with the Vulkan shim's fixes, fragment density maps hidden, space warp off and without
Valve's VALVE_rpo layer (random jumping polygons in 3D without the last two, as in Into The Radius 2).
details: Unreal 5.2 (Vulkan) quit itself (ForceQuit, use_alt), then crashed three times in the Frame's Vulkan driver
(Turnip) on things Quest's driver ignores - a depth resolve in a subpass without a depth attachment, image barriers
and image views for a missing image. Unreal turns on fragment-density-map foveation because the driver offers the
extension and then expects the density map from the headset, which the Frame never provides; vk_hide_fdm hides the
extension from the game (Valve's own foveation layer is unaffected).
tested_version: 1.0-916944
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
use_alt: true
adapter:
vk_spec_fixes: 1
vk_hide_fdm: 1
hide_space_warp: 1
lepton_env:
VK_INSTANCE_LAYERS: VK_LAYER_VALVE_fdm_injection
verified:
date: '2026-10-06'
updated: '2026-10-06'
source_hint: Metro Awakening
@@ -0,0 +1,22 @@
package: com.zenstudios.PFXVRQuest
title: Pinball FX VR
status: issues
notes: Plays; mixed reality mode not working yet. Space warp off (fewer stutters).
tested_version: '1.9'
engine: Unreal
xr: OpenXR
alt_overport:
- patch_remove_unreal_force_quit
adapter:
equirect_emul: 1
hide_space_warp: 1
verified:
date: '2026-10-05'
known_good_sha256: ec5491f6a809c0ee9624e4a43aa0f2c307eb048763492d32a00ff4e0511efe54
app: 0.9.1
overport_cli: 1.2.5
frame_build: '20260930.6234839'
agent: 48
issue: 50
updated: '2026-10-06'
source_hint: Pinball FX VR
+21
View File
@@ -0,0 +1,21 @@
package: io.ARVORE.TheBoysVR
title: The Boys VR
status: works
notes: Plays with space warp off (owner's headset test, 2026-10-06; black screen reported before).
tested_version: 1.1.0.345
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
hide_space_warp: 1
verified:
date: '2026-10-06'
known_good_sha256: 5df46b1771611c607229ee59298d983a4d78a57591d4864a02da2df5d2b6f97b
app: 0.12.0
updated: '2026-10-06'
min_app: 0.12.0
source_hint: The Boys
+21
View File
@@ -0,0 +1,21 @@
package: jp.co.amata.nvr
title: The Tale of Onogoro
status: works
tested_version: 1.1.0248
engine: Unity
xr: OpenXR
frame:
- frame.unity_text_input
device:
- device.text_input_window
adapter:
haptic_fix: 1
verified:
date: '2026-10-08'
known_good_sha256: d6258a22a0a6e4588bbec36170f126bffc44ed64784f99e37cf4b03ad212fb79
app: 0.12.0
overport_cli: 1.2.5
frame_build: '20261006.6173745'
agent: 59
issue: 108
source_hint: The Tale of Onogoro
+18
View File
@@ -0,0 +1,18 @@
package: org.timecrisis.quest
title: Time Crisis VR (Experimental)
status: works
notes: Fully playable at 120hz
tested_version: 0.8.3
engine: Other
xr: OpenXR
frame:
- frame.sdl_clipboard
verified:
date: '2026-10-06'
known_good_sha256: 4e67411a8e9c0b5fbb19ca7908c4222aa5ad1b2d47a8f4b5018b4fe9c2f5324e
app: 0.12.0
overport_cli: 1.2.3
frame_build: '20261005.6135832'
agent: 59
issue: 80
source_hint: TimeCrisisVR-v0.8.3-quest
+29
View File
@@ -0,0 +1,29 @@
package: org.wiicompiled.quest
title: WiiCompiled VR
status: issues
notes: 'To add a game: in FramePort''s Files tab, upload your .wcgame file to this game''s storage, folder
Android/data/org.wiicompiled.quest/files/WiiCompiledOpenXRVR/Import, then open WiiCompiled (it imports the newest
file there; one at a time). Once your game is imported, turn on "Start straight in VR" (and off "Show the app''s
Android window") and update it on the Frame: it then opens in VR without the flat launcher window, which otherwise
stays in view (turn it off again to import another game). The right eye jitters during races.'
details: A native Mario Kart Wii recompilation (needs your own disc as .wcgame files built by the WiiCompiled
launcher on a computer). Lepton's Android has no document picker, so the launcher's "Import from computer" and
"select disc image" buttons fail (ActivityNotFoundException for OPEN_DOCUMENT); its Import folder is read when the
launcher opens instead. The game's libmain.so has its own OpenXR loader and talks to the Frame's runtime directly
(FrameBridge isn't in its path); the right-eye jitter in races comes from its stereo replay of the race view, so it
needs a fix in WiiCompiled itself. The launcher is a flat Android window (shown with lepton-show-flatscreen) that
stays in view after it starts the VR part (QuestActivity, process :game); frame.start_activity makes QuestActivity
the start activity (owner-verified 2026-10-05, opens straight in VR), but it skips the launcher's import step, so it
stays off by default.
tested_version: 0.4.0-quest
engine: Other
xr: OpenXR
frame:
- frame.sdl_clipboard
- frame.vk_sanitize
device:
- device.text_input_window
verified:
date: '2026-10-04'
updated: '2026-10-05'
source_hint: WiiCompiled
+23
View File
@@ -0,0 +1,23 @@
package: rift.beat_saber
title: Beat Saber
status: works
notes: 'Supports SteamVR/OpenXR itself: runs directly, without Revive.'
engine: Unity
xr: OpenXR
kind: rift
quest_package: com.beatgames.beatsaber.lj369vr
pcvr:
- pcvr.xr_timefix
- pcvr.steamvr_tuning
pcvr_remove:
- pcvr.revive
as_is: true
verified:
date: '2026-10-09'
known_good_sha256: dc80bd1f8e46e7b7cdc4fbf51a84e68f2918d7481581bee9c21f65e269c6bf8b
app: 0.12.1.dev232
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 67
issue: 117
source_hint: Beat Saber
@@ -0,0 +1,23 @@
package: rift.eleven_table_tennis_vr
title: 'Eleven: Table Tennis VR'
status: works
notes: 'Supports SteamVR/OpenXR itself: runs directly, without Revive (arguments -vrmode OpenVR).'
engine: Unity
xr: LibOVR+OpenVR
kind: rift
pcvr:
- pcvr.launch_args
- pcvr.xr_timefix
- pcvr.steamvr_tuning
pcvr_remove:
- pcvr.revive
as_is: true
verified:
date: '2026-10-09'
known_good_sha256: 2cdfe3b096aef0bf76726156699381f7847ca4d17e7222359521982778470705
app: 0.12.1.dev232
overport_cli: 1.2.5
frame_build: '20261007.6125817'
agent: 67
issue: 118
source_hint: Eleven Table Tennis VR
Loaded 100 of 525 files, more files were not shown because too many files have changed in this diff. Show more