19 Commits
Author SHA1 Message Date
saphidandClaude Opus 5.5 63c1a9ff55 docs: xrdp sign-in from Windows verified on a real Frame
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 20:25:49 +10:00
Alex SouthwellandClaude Opus 5.5 e702adbd77 Live view: a Desktop view that stays still, and Control to tap on the Frame (#46)
* Live view: a Desktop view that stays still, and Control to tap on the Frame

The live view gets a second source and a way to use the Frame from it:

- Desktop: the app panel in use in the headset, streamed from its own window
  (x11grab of gamescope's redirected window), so it doesn't move as the
  wearer looks around. A picker shows any other panel, view only.
- Control: on the Desktop view a tap or click lands exactly where you put it;
  drag is a mouse drag, press and hold right-clicks, two fingers scroll, and
  on a computer the mouse, wheel and keyboard work directly. On the headset
  view the view is a trackpad. A text field and key row type from a phone.

Input goes through gamescope's own EIS socket (the way Steam feeds Remote
Play input) with the libei already on the image: ui/frame_touch.py, over
the same long-lived ssh machinery as the keyboard agent, nothing to
install. It reaches the panel that has focus on either X display, which
the KDE Connect route can't. Verified on the Frame and from the iPhone app
in the Simulator.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: fixes from review

- Keys held on the Frame are released with buttons when Control stops or
  the view loses focus; keys for the Frame no longer trigger Frame Control's
  own shortcuts.
- Taps only act when the picture on screen is the panel in use; positions,
  presses, keys, text and scrolls name their panel (display and window: ids
  repeat across :0 and :1, told apart by pid), and the Frame drops them if
  focus has moved on. Releases always go.
- While connecting, a tap keeps its position; on an error only releases wait
  and retries back off; trimming a long queue never drops a release.
- Lifting one of two scrolling fingers ends the scroll; a cancelled touch
  isn't a tap; clicks and holds on the bars around the picture do nothing.
- A capture loop from before a Live restart can't stop the new video.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: close the targeting gaps from the second review

- The focused panel's display comes from GAMESCOPE_FOCUS_DISPLAY (gamescope
  packs ":1" into the first value), so a window id repeated across :0 and :1
  can't be mistaken; the pid is only the fallback.
- Presses, keys, text and scrolls read focus afresh on the Frame; only moves
  use a reading up to a second old.
- A gesture remembers the panel it started on and does nothing more if that
  stops being the one in use; a press with no panel to aim at isn't sent.
- Opening a screenshot clears the panel Control would act on; switching to
  another app releases held keys and buttons.
- Trimming keeps a click with its position; the error backoff holds for new
  input too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: fixes from the SWE-2 Max review

- The Frame side tracks keys as well as buttons and lets go of both when the
  session ends.
- A stale tap tells the page, which re-reads the panels at once.
- A paused input device waits instead of ending the session; only a
  disconnect does. An OS error on one event skips it.
- Presses check focus with two property reads and do the full lookup only
  when it changed.
- Writes to an agent's stdin are serialized, so two devices sending at once
  can't tear a line (the keyboard agent too).
- Connecting gives up with a message after 15 s instead of hanging on
  "Connecting…"; text goes in 100-character pieces so releases don't wait
  behind a long paste; a cancelled mouse gesture releases what's held.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: stale clears, pauses reconverge, pastes split per request

- The Frame says it has caught up as soon as an aimed event lands after a
  stale one, so the page stops re-reading the panels.
- After a device pause it lets go of everything it holds (releases that
  arrived while paused were dropped), and waits for the device once per
  batch, not once per event.
- The quick focus check no longer freshens the panel geometry's age.
- Each request carries at most about 100 characters of text.
- Turning Control off while it connects doesn't report an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* frame_touch: build the socket path on the Frame, so Windows can import it for tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* frame_touch: any event that goes through clears the stale flag

A trackpad move names no panel, so waiting for an aimed event could leave
the page re-reading panels for the rest of the session; a release still
aimed at the old panel doesn't count.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 11:13:21 +10:00
Alex Southwell ef56025ad1 Merge pull request #19 from saphid/frame-input
Keyboard and trackpad for the Frame, through its own KDE Connect
2026-09-29 10:33:35 +10:00
saphidandClaude Opus 5.5 4bb7a1ee86 Merge main into frame-input: keyboard and trackpad alongside analytics, the Mac view and MCP
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:25:26 +10:00
saphid ae7f733b90 Merge remote-tracking branch 'origin/main' into theatre-media
# Conflicts:
#	ui/server.py
2026-09-29 10:21:27 +10:00
saphid b0d6039eec Merge remote-tracking branch 'origin/main' into theatre-media
# Conflicts:
#	docs/testing.md
#	ui/server.py
2026-09-29 10:08:45 +10:00
saphidandClaude Opus 5.5 f7573e3565 Merge main into mac-in-headset (MCP agent routes alongside the Mac view); skip the bash syntax test on Windows
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:41:24 +10:00
saphid 0d448ab510 Add owned OpenVR media playback and stereo previews 2026-09-28 22:33:50 +10:00
saphid a6137351d9 docs: record Linux VR client blockers and streaming options 2026-09-28 22:23:19 +10:00
saphidandClaude Opus 5.5 5bf1268c82 Ship KDE Connect inside Frame Control instead of downloading it on the Frame
The keyboard and trackpad no longer fetch KDE Connect from Valve's package
repository on the Frame. The desktop apps and the iPhone app's Frame bundle
carry Valve's arm64 build of kdeconnect 24.02.2-1 and the five libraries it
links (kcontacts, kpeople, modemmanager-qt, pulseaudio-qt, libfakekey),
pinned by SHA-256 in frame/kdeconnect/packages.json and downloaded at build
time from the kdeconnect-frame-24.02.2-1 release, which also holds Valve's
complete source package for each.

On first use the computer copies them over its SSH connection (the iPhone
bundle already has them on the Frame); the agent checks each SHA-256,
unpacks them and stamps which build it is, so later starts copy nothing.
No internet on the Frame, 3.6 MB instead of 8 MB, 18 MB unpacked instead of
82 MB (ModemManager and friends were packaging-only dependencies).

GPL/LGPL compliance: frame/kdeconnect/NOTICE.md names each exact version,
licence and source; per-project licence texts in frame/kdeconnect/LICENSES;
THIRD_PARTY_NOTICES.md; an About and licences dialog in the app.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:07:20 +10:00
saphidandClaude Opus 5.5 71200c5179 Merge origin/main into mac-in-headset
Brings in #4, #5, #8 (fbl100's verified Remmina/VNC mirror), APK
alternatives and the website. docs/streaming.md: Mac in the headset stays
the recommendation (now verified on the Frame); Remmina keeps #8's verified
evidence as the whole-screen fallback. docs/mac-in-headset.md cites #8's
lag finding.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:03:34 +10:00
saphid 6217b5f2fa Merge remote-tracking branch 'origin/main' into frame-input 2026-09-28 17:43:27 +10:00
saphidandClaude Opus 5.5 b9e31178f3 Keyboard and trackpad for the Frame, through its own KDE Connect
Home → Keyboard and trackpad, in every version of Frame Control (Mac,
Windows, Linux, iPhone, iPad) with nothing to install on the device in
your hand. On a phone: a trackpad (drag, tap, two-finger scroll and
right-click) and a field that types on the Frame. On a computer: click
the pad to pass the mouse and keyboard through; Esc to stop.

First-party route: ui/frame_input_agent.py runs on the Frame and talks
KDE Connect's LAN protocol (v7) to kdeconnectd as if it were a phone.
KDE Connect isn't on the image, but Valve's package repository has it;
the agent fetches it and four libraries into ~ (no root, survives
updates), starts it, pairs by itself (accepting over D-Bus), and stops
it again when the last device disconnects. Each device has its own
identity; a stuck KDE Connect is restarted once.

Verified against the real Frame (SteamOS 0.4.1): first-time install,
pairing, pointer moves from the Mac's server and the iPhone app
(Simulator), Mac and iPhone at once, two installs at once, a frozen
daemon replaced, and the daemon stopping when the app quits.

Reviewed by GPT-6 Astra (xhigh) over seven rounds; all findings fixed
except per-event delivery acknowledgement (documented known limit).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 17:42:19 +10:00
Alex Southwell ff2c4ebfe0 Merge pull request #8 from fbl100/mac-mirror-verified
Mac → Frame mirror: verified, with fixes for scaling, login and the cursor
2026-09-28 17:20:22 +10:00
saphidandClaude Opus 5.5 a3c6e5c984 Mac in the headset: stream Mac windows and screens into the Frame as panels
Frame Control can now show any Mac window, or a whole screen, as its own
SteamVR panel on the Steam Frame (Tools -> Mac in the headset, macOS only).
Place it with the SteamVR dashboard; the laser clicks and scrolls, and the
Mac's own keyboard types.

- mac/frame-mac-view (Swift, no dependencies): ScreenCaptureKit capture per
  window or display, VideoToolbox H.264 with low-latency rate control (JPEG
  fallback), a loopback HTTP/WebSocket server, CGEvent/AX input playback,
  and a display-awake assertion while anyone watches.
- ui/frame_macview.py: starts the agent, runs an ssh -R tunnel with a
  supervisor that reopens it on the same port, and launches a Chromium app
  window per stream on gamescope's :0, tagged with STEAM_GAME for its own panel.
- Frame Control's key never leaves the Mac: viewers get single-use,
  per-source tickets and reconnect keys that Stop revokes.
- ui/mac-view.html: WebCodecs decode, keyframe recovery, pointer/wheel/keys back.
- Bundled in the Mac app build; tests/test_macview.py builds and drives the
  agent on macOS.

Verified on the Frame (build 20260925.6191901) with the test pattern: panel
in about 1.5 s, about 60 fps, Mac-to-window about 11-17 ms, tunnel recovery
in 4 s. Laser input and real window capture still need a person in the headset.

Also commits the other thread's first-party rule (steam-frame skill) and
the first-party options table in docs/streaming.md.

Reviewed by GPT-6 Astra (xhigh, read-only) over six rounds; all findings fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 13:33:46 +10:00
Frank LevineandClaude Opus 5.5 5e12245932 Streaming doc: Mac → Frame mirror verified; move answered open questions
Tested on Frame BUILD_ID 20260925.6191901 with macOS 27.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 13:49:12 -04:00
saphidandClaude Opus 5.5 fe87a9d826 Keep the page clear of iOS safe areas everywhere; research typing, pointing and mirroring into the Frame
- Header, content, tab bar, status strip, drawer and toasts add the notch,
  Dynamic Island, rounded-corner and home-indicator insets on every side
  (zero on desktops). Phones on their side use the bottom tab bar layout.
- The phone tab bar hides while a text field has focus, instead of riding
  on the keyboard.
- DEBUG hook FRAME_TEST_LANDSCAPE for checking this in the Simulator.
- docs/streaming.md: iPhone mirroring (UxPlay, broadcast extension) and
  keyboard/mouse input (uinput needs no sudo on the Frame, verified).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 21:26:32 +10:00
saphidandClaude Opus 5.5 99653151c4 Address review findings in the app, server and tests
- app: startup shell, python and ssh probes run asynchronously so a slow
  shell profile can't freeze the window; PATH comes from the user's real
  login shell and a failed lookup isn't cached; a server that never
  answers is killed; the setup offer runs once per launch, only after the
  UI loads, and decides from HostName alone; connect.sh is started through
  `env ... zsh` so it works whatever the login shell is.
- server: volume validates the level before muting or changing anything.
- Steam: null-safe install-manager fields, http.client errors caught in
  store ratings, price fallback when a sale has no final price.
- tests: server output kept for diagnosis, any startup error retried, and
  captures asserted non-cacheable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 22:44:54 +10:00
saphidandClaude Opus 5.5 1f6115b789 Steam Frame from a Mac: research docs and helper scripts
README with the minimum-typing checklist (Developer Mode toggle + Set User
Password; the rest runs from the Mac), docs for SSH, streaming, file
transfer, and open questions with sourced confidence levels, plus Mac-side
zsh helpers and a fallback headset bootstrap.

Scripts are UNTESTED against hardware: checked with zsh -n / bash -n /
shellcheck only. Two SWE-2 Max read-only review passes (devin -p --model
swe-2-max); verified findings fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 15:38:43 +10:00