mirror of
https://github.com/spoopyghosty0/frameport.git
synced 2026-10-10 14:00:46 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8167cb86c6 | ||
|
|
44bc689348 | ||
|
|
007db344d7 | ||
|
|
3fb2621030 | ||
|
|
39ca9a5f0d | ||
|
|
e64e8a95e0 | ||
|
|
69e888c7fe | ||
|
|
ce809c432d | ||
|
|
26cee1551e | ||
|
|
f812ea8716 | ||
|
|
3dc0a95379 | ||
|
|
f8244f582d | ||
|
|
69fbdfdc4a | ||
|
|
ef3272a31b | ||
|
|
b0f3ef2698 | ||
|
|
1711e7f7d9 | ||
|
|
ff6cdf3b6a | ||
|
|
28517a1999 | ||
|
|
af9c207ddf | ||
|
|
88045bcf4e | ||
|
|
5147710fad | ||
|
|
9c45cff09a | ||
|
|
b4848c0424 | ||
|
|
3a46b78361 | ||
|
|
75bbc6eb5f | ||
|
|
da638aea99 | ||
|
|
7c37b479db | ||
|
|
fa473c5ada | ||
|
|
1e6ce04e4f | ||
|
|
5cd5b119e7 | ||
|
|
186138cc3c | ||
|
|
98c7ca980a | ||
|
|
b2470b962a | ||
|
|
2a705bc6d1 | ||
|
|
5d44831757 | ||
|
|
456880501b | ||
|
|
63f7ae12e1 | ||
|
|
fa69ffefd2 | ||
|
|
f78bc82cc4 | ||
|
|
dfacf6a206 | ||
|
|
b2f14c1e2e | ||
|
|
03d7a311bf | ||
|
|
cd5119278b | ||
|
|
6ab3608a44 | ||
|
|
c0539af368 | ||
|
|
c6363140f4 | ||
|
|
187105b729 | ||
|
|
b983c0f11f | ||
|
|
c7cee33889 | ||
|
|
d9d73b8aec | ||
|
|
48455b9b72 | ||
|
|
af798c0bf3 | ||
|
|
ed714c9d65 | ||
|
|
832b401630 | ||
|
|
114b7cb4d6 | ||
|
|
a4d3ce5e00 | ||
|
|
b3095b110a | ||
|
|
fb284b6fc4 | ||
|
|
c0df52b981 | ||
|
|
a1b0a3f350 | ||
|
|
df864e9fed | ||
|
|
6595a31048 | ||
|
|
f4bcb658e1 | ||
|
|
e4f70144e9 | ||
|
|
020334b37b | ||
|
|
24a98ab263 | ||
|
|
58563b99a5 | ||
|
|
9013a7d13c | ||
|
|
f36a17b46a | ||
|
|
7335ff2ce5 | ||
|
|
21c039f9b3 | ||
|
|
8814b1ce56 | ||
|
|
3e8a480ea6 | ||
|
|
ea2cd893b4 | ||
|
|
a90a8c27dc | ||
|
|
9d0d72c40a | ||
|
|
56d2ac117f | ||
|
|
cb8202d891 | ||
|
|
029b0674d1 | ||
|
|
c852473a43 | ||
|
|
acf1ef1da2 | ||
|
|
5fe120e897 | ||
|
|
41624c8dbd | ||
|
|
e8ec39db86 | ||
|
|
936d4b188b | ||
|
|
e9ab1489cc | ||
|
|
1043eb1d1b | ||
|
|
0f444da595 | ||
|
|
fda644d036 | ||
|
|
fa0fbbd29a | ||
|
|
3446999109 | ||
|
|
e9eedb2241 | ||
|
|
d3a35c307a | ||
|
|
d6f87f79a6 | ||
|
|
24a1ef9f1d | ||
|
|
ae4904c7d9 | ||
|
|
b142f7c0ac | ||
|
|
934f356927 | ||
|
|
a61764960d | ||
|
|
55a376cdfd | ||
|
|
da7655ee25 | ||
|
|
0ae754fa5d | ||
|
|
ecfd2408cf | ||
|
|
44dfd43692 | ||
|
|
29876ec046 | ||
|
|
3667f504ec | ||
|
|
375b976dcd | ||
|
|
2a74e5ff64 | ||
|
|
0c623c2efc | ||
|
|
d49b3ae884 | ||
|
|
f811261507 | ||
|
|
ec701e6e56 | ||
|
|
360dc105e1 | ||
|
|
892c7c13bd | ||
|
|
3b6128a1b0 | ||
|
|
4c42a528bd | ||
|
|
0e7c5264a0 | ||
|
|
69a4fa6fa7 | ||
|
|
e6b9808beb | ||
|
|
b34330dc85 | ||
|
|
ae69fe3831 | ||
|
|
6d2dc95cc8 | ||
|
|
474be9d34b | ||
|
|
7b4dff7d84 | ||
|
|
885070a00c | ||
|
|
67b58238a0 | ||
|
|
a1c87618f6 | ||
|
|
b4cec19283 | ||
|
|
109c7e449c | ||
|
|
05ad7e4d25 | ||
|
|
1e96abebbb | ||
|
|
69da709ea2 | ||
|
|
d5f9c248e0 | ||
|
|
cc39547e33 | ||
|
|
096d24e42b | ||
|
|
2995413434 | ||
|
|
4b34dbd218 | ||
|
|
a775e63e6d | ||
|
|
3cd4affcf6 | ||
|
|
51e553039a | ||
|
|
27ff49a137 | ||
|
|
e70acf9269 | ||
|
|
1f6fce0fcc | ||
|
|
188cb8fe68 | ||
|
|
0744a126cb | ||
|
|
1c8a0d63e7 | ||
|
|
124ec594a6 | ||
|
|
90b528f9f2 | ||
|
|
2da6082166 | ||
|
|
3e61b07254 | ||
|
|
48c3716ef5 | ||
|
|
dca2d8b762 | ||
|
|
2c4bbdbfec | ||
|
|
8a08733be8 | ||
|
|
d7193bea19 | ||
|
|
c3522a05bb | ||
|
|
8a9a428f1e | ||
|
|
919d059add | ||
|
|
674c26f2d9 | ||
|
|
a6daa5cccb | ||
|
|
6f89123017 | ||
|
|
518c94d79f | ||
|
|
edf9f494e8 | ||
|
|
0db053c31f | ||
|
|
7439f082db | ||
|
|
f12f4aec4c | ||
|
|
8d95592f53 | ||
|
|
44d23f778d | ||
|
|
7a40e47e67 | ||
|
|
9401b7fc87 | ||
|
|
e510ea88f0 | ||
|
|
4c2b6c9dee | ||
|
|
cb689c576a | ||
|
|
bd2e1a8410 | ||
|
|
608fac9d68 | ||
|
|
919c0e291e | ||
|
|
23f4192cfd | ||
|
|
3391a981b8 | ||
|
|
271ce56d08 | ||
|
|
0e47ce8f1a | ||
|
|
ad924669d3 | ||
|
|
311277ae40 | ||
|
|
bad59bfb5b | ||
|
|
9b57c4753f | ||
|
|
1301e60be1 | ||
|
|
069a74f97e | ||
|
|
683ae5bcf6 | ||
|
|
af904c62e6 | ||
|
|
f2d93af973 | ||
|
|
59fb47a827 | ||
|
|
9e169e069b | ||
|
|
eed6e4aaed | ||
|
|
9829ee1666 | ||
|
|
13069db28a | ||
|
|
7058105056 | ||
|
|
df5b949f1a | ||
|
|
3929ff0a8b | ||
|
|
4910440f56 | ||
|
|
bda9045be6 | ||
|
|
a7890d46de | ||
|
|
50ab3eb341 | ||
|
|
4313b52792 | ||
|
|
4f9ecf4801 | ||
|
|
9a5efa28f5 | ||
|
|
cf900cd9d4 | ||
|
|
ef21b33ca2 | ||
|
|
799f1bd9f1 | ||
|
|
44a056095d | ||
|
|
6037b13e88 | ||
|
|
c3a34ace99 | ||
|
|
05843633a7 | ||
|
|
5198f704e9 | ||
|
|
eeee7d2b84 | ||
|
|
772c26d91a | ||
|
|
db0a78ccc3 | ||
|
|
01d764e05c | ||
|
|
0c5c1638ed | ||
|
|
a49cfb0b57 | ||
|
|
0f975d2233 | ||
|
|
ccff9ab486 | ||
|
|
f2cf7db507 | ||
|
|
2f740bbb41 | ||
|
|
1462d3d471 | ||
|
|
22d10c1ff0 | ||
|
|
8b9657b2e6 | ||
|
|
bc6f6b7fe2 | ||
|
|
8f3c8b33ba | ||
|
|
8187c79d17 | ||
|
|
2ecf7f8624 | ||
|
|
6200662bc7 | ||
|
|
d2c72264be | ||
|
|
f37f7be9c7 | ||
|
|
d05dd27971 | ||
|
|
fd478f4c70 | ||
|
|
d834ffac42 | ||
|
|
3e11175001 | ||
|
|
85a11061d0 | ||
|
|
e26cb8b0db | ||
|
|
208d7bb4dd | ||
|
|
cf1a2c9181 | ||
|
|
ba9ccc3606 | ||
|
|
83a614d645 | ||
|
|
5734c1fdee | ||
|
|
af791a45b4 | ||
|
|
11c8802b07 | ||
|
|
70d519a5a9 | ||
|
|
4e00c88949 | ||
|
|
1b62d643f3 | ||
|
|
6bd4eb523f | ||
|
|
d22123c657 | ||
|
|
0137cd993b | ||
|
|
7b8e7c2c5d | ||
|
|
990331e5b6 | ||
|
|
56b370f582 | ||
|
|
ac628cd284 | ||
|
|
c12b2f6992 | ||
|
|
a110e8573f | ||
|
|
4fdeeaf829 | ||
|
|
dbabb37343 | ||
|
|
7afee4bf59 | ||
|
|
7367a35176 | ||
|
|
9948f946c5 | ||
|
|
3870500972 | ||
|
|
a7b02c00ee | ||
|
|
09c7bb6ea7 | ||
|
|
3761dfd62d | ||
|
|
f86d9021f9 | ||
|
|
83e901a682 | ||
|
|
246e5fc5ee | ||
|
|
17403779cb | ||
|
|
0e03e061a4 | ||
|
|
d8cf19fb20 | ||
|
|
7cd9a38eaf | ||
|
|
4f3593192f | ||
|
|
974426d1d0 | ||
|
|
b7a0e0cb5b | ||
|
|
38edc26092 | ||
|
|
e96e25bade | ||
|
|
67c991ca4f | ||
|
|
d2017194f3 | ||
|
|
7a11706b3a | ||
|
|
76d4390b19 | ||
|
|
2022d9986a | ||
|
|
9ff7edf93b | ||
|
|
a5722b50a0 | ||
|
|
0a13ca72a2 | ||
|
|
c53d754007 | ||
|
|
a1662da17d | ||
|
|
0141bad259 | ||
|
|
6ed95684dc | ||
|
|
a6ca8385a9 | ||
|
|
210410f125 | ||
|
|
7e2502a552 | ||
|
|
a57d89e874 | ||
|
|
aade29982f | ||
|
|
d94cab6048 | ||
|
|
f17fdbf271 | ||
|
|
fb70c09d72 | ||
|
|
69bf2700e1 | ||
|
|
0b28da5521 | ||
|
|
9e9a4c0f6c | ||
|
|
bb3f6b9e7c | ||
|
|
dc7533e4e1 | ||
|
|
3660167bd8 | ||
|
|
6a47fad8f7 | ||
|
|
0f8062f881 | ||
|
|
65369f154c | ||
|
|
aefb5adc07 | ||
|
|
5603edeef7 | ||
|
|
5c47185938 | ||
|
|
fefdc19cac | ||
|
|
db6ccece32 | ||
|
|
59018cb396 | ||
|
|
70216de397 | ||
|
|
bef61563d5 | ||
|
|
1b728d7c75 | ||
|
|
60cde5f846 | ||
|
|
c3a63bbd85 | ||
|
|
bbe76ab888 | ||
|
|
b89e48cec0 | ||
|
|
dc020a2cb7 | ||
|
|
cc3febfae4 | ||
|
|
e729f3f4bc | ||
|
|
2fecfbf6ea | ||
|
|
6e0bb8ee59 | ||
|
|
26679114ed | ||
|
|
b8e49a3419 | ||
|
|
f196cf556d | ||
|
|
1b0345b15b | ||
|
|
4508608dcf | ||
|
|
3e16199e64 | ||
|
|
a7fa1c06d7 | ||
|
|
dabd9b2095 | ||
|
|
0774536473 | ||
|
|
4a7fe3645c | ||
|
|
204aa70ada | ||
|
|
8bb3df0ec8 | ||
|
|
d9f9695360 | ||
|
|
d45d391683 | ||
|
|
b0682ee570 | ||
|
|
d1cf305c0a | ||
|
|
d22f416489 | ||
|
|
2dc92a090f | ||
|
|
23a47880e0 | ||
|
|
da399ef77a | ||
|
|
f0192c0e9d | ||
|
|
cad54bb2dd | ||
|
|
507dd4ca6e | ||
|
|
a361cdc84d | ||
|
|
fa7567503f | ||
|
|
1c90669eb4 | ||
|
|
942a71dd54 | ||
|
|
e462907c49 | ||
|
|
60efbbe7a9 | ||
|
|
321588d94b | ||
|
|
b4ae5e0023 | ||
|
|
4ba148908a | ||
|
|
7af21e17ce | ||
|
|
fa3544565a | ||
|
|
f7b59a75b3 | ||
|
|
58eaab3c19 | ||
|
|
3d32be1a98 | ||
|
|
8da5a44efb | ||
|
|
51f0a5d75c | ||
|
|
b06cc9659b | ||
|
|
bc40325c2d | ||
|
|
82c2209b6f |
No files matched your search
+90
-10
@@ -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"
|
||||
@@ -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/
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
[](https://github.com/spoopyghosty0/frameport/releases/latest)
|
||||
[](https://github.com/spoopyghosty0/frameport/actions/workflows/build.yml)
|
||||
[](https://github.com/spoopyghosty0/frameport/releases)
|
||||
[](LICENSE)
|
||||

|
||||

|
||||
|
||||
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.
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
@@ -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.
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+18
-6
@@ -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.
@@ -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.
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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+
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in new issue
Block a user