Commit Graph
22 Commits
Author SHA1 Message Date
DeeJanuzandClaude Opus 5.5 3fe498ffc3 Merge branch 'hands-r6' into experimental: hand tracking as the main input
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:32:45 -06:00
DeeJanuzandClaude Opus 5.5 a0e46e4954 gaze: keep SteamVR's eye cameras at 90 fps (gaze/eye-rate.py)
The Frame's SteamVR driver runs the eye cameras at 15 to 90 fps and, with its
defaults, picks 15. Our tracker then sees 8 or 9 frames in a calibration
dot's 0.6 s, where it needs 15, so it can never calibrate (2026-10-10 report:
"the right eye was seen in only 8 frames" on all 27 dots). With
steamvr.gazeDepEyeToHeadEnable on, SteamVR asks for 90 at every start; the
reporter calibrated once it was on.

gaze/run.sh install turns it on (vrcmd with SteamVR running, else the
settings file), and marks it as Frametop's; gaze/run.sh uninstall and
uninstall.sh turn it off only then. update-check.py (doctor) and
gaze-report.py report the cameras' rate from eyetracking.txt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:58:26 -06:00
DeeJanuzandClaude Opus 5.5 2c472879ed Spotwatch: Meta+Space search for apps and remote displays
A Spotlight-like search pill (docs/spotwatch.md). Meta+Space (the input
relay's new spotwatch action, bindable to mouse and controller buttons
too) opens a faux-glass pill straight ahead of the head. Typing finds
apps and remote displays ({host} - {display}). Enter brings a running
app's most recent window to the front with the lazy susan, launches an
app that isn't running as a floating window, or connects and spins to a
remote display. Shift+Enter or a right click opens the item's menu: the
app's desktop actions, Open new window, Open docked on this screen, and
its windows; a display's Go to and Disconnect.

- spotwatch/ft-spotwatch (Python, in the Plasma session's autostart):
  the index, ranking (spotsearch.py), keys via libxkbcommon, usage.
- spotwatch/ft-spotpanel.cpp (SteamVR overlay, built by
  screens/build.sh): the pill, drawn on the CPU; --render for a look
  without a headset.
- ft-screens: "spin to N", "front N", and "spotwatch on|off", which
  routes every key to the search while it's open (a lease, renewed
  every second) and dismisses it on a click elsewhere or a pause.
- ft-floatd: "spotlist", "activate ID", and launch action=/screen=;
  the KWin script tracks when each window was last active.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 12:08:59 -06:00
DeeJanuz ca1e5c38ab Merge branch 'experimental' into hands-full: a Mac's real monitors through Sunshine, Frametop Voice
# Conflicts:
#	input-settings/ft_input_settings.py
#	input-settings/main.qml
#	input/game_pause.py
#	session/frametop.conf.example
2026-10-10 11:01:32 -06:00
DeeJanuzandClaude Opus 5.5 b3275e7843 Voice: frame-voice becomes Frametop Voice, installed with Frametop
voice/ft-voiced (was frame_voice.py) runs in Frametop's container as
frametop-voice.service. It keeps the mic, the wake word and live text,
and hands the keyboard side to the input relay:
- push-to-talk keys are key combinations (dictate, dictate_hold); the
  relay sends "toggle|start|stop" to @frametop_voice, taken only from
  this user
- text goes to the relay as "type TEXT" (ASCII, in pieces of 2000
  bytes), so it lands where typing goes; the relay holds it back while
  a modifier is held
- controller buttons are read from vrserver's web socket with
  input/vrws.py, in a thread, so the websockets package goes
No own uinput keyboard, fd store, evdev, or controller service any more.
whisper-server runs only while the wake word is on, started and stopped
by ft-voiced. Voice commands and hooks run on the host through
distrobox-host-exec (env passed through env(1)); their FRAME_VOICE_*
variables keep frame-voice's names.

Settings: ~/.config/frametop-voice.json (voice_settings.py, standard
library), wake word off by default, "advanced" for the old config.toml
tunables. voice/run.sh install carries frame-voice's settings over once
(its keys become key combinations) and turns the standalone units off.

Install: install.sh step 8/11 asks (yes by default; --no-voice through
get.sh, install-release.sh and a FrameDrop checkbox). voice/build.sh
builds whisper-server (whisper.cpp d09f61a, Vulkan, static) and
build/venv; voice/models.sh fetches the 322 MB of models into
~/.local/share/frametop/voice by fixed URL and sha256. The image gets
glslc, spirv-headers-devel and pipewire-utils, uv.lock a voice group (sherpa-onnx with its
core pinned: uv dropped it), CI smoke whisper-server and the venv.
uninstall.sh asks about the models; update-check and report.sh know the
service (report.sh leaves out the lines with what was said).

Tests: voice/test (settings, carrying over, typing through a stand-in
relay, push-to-talk, controller buttons from a stand-in web socket) in
just test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 09:18:14 -06:00
DeeJanuzandClaude Opus 5.5 700f534a27 ft-notifyfwd: settings state from its last state line; keep "on" out of the way
- Display Settings read the log's last line, so an error logged after
  "forwarding" (a failed Notify) showed "In the desktop" while forwarding.
  It takes the last state line now.
- "on" also forwards to SteamOS's steam_notif_daemon, where notifications are
  lost while Plasma's popups are off. The settings app shows it only while
  frametop.conf has it, with that warning.
- update-check reads libnotificationmanager.so.1 (its soname) first; the
  unversioned .so is a dev symlink.
- justfile: why session/test/test_notifyfwd.py isn't in test-python.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:33:12 -06:00
DeeJanuzandClaude Opus 5.5 995d407328 Merge utrack/notify-forward: forward the desktop's notifications to the Steam session (#48)
From https://github.com/utrack/frametop/tree/notify-forward. docs/reference.md:
kept both the notifications paragraph and experimental's three-autostart one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:32:06 -06:00
DeeJanuzandClaude Opus 5.5 4c348e6b2b Merge experimental into hands-full (SteamOS 0.4.5 fixes)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:38:59 -06:00
DeeJanuzandClaude Opus 5.5 185cb766b1 SteamOS updates: keep the Bluetooth fixes and the eye grabber through them
A SteamOS update deletes every /etc file its keep list
(/usr/lib/rauc/atomic-update-keep.conf) doesn't name. The list keeps
units but not what they run, so after the 0.4.5 update
steamframe-bt-fixups.service and frametop-eyegrab.service failed with
203/EXEC: Bluetooth LE devices stopped reconnecting, and gaze mode fell
back to SteamVR's tracker, which had no calibration.

- Both installers add a drop-in to /etc/atomic-update.conf.d naming
  their file; uninstall removes it.
- update-check.py (doctor.sh) fails when a unit's program is gone and
  warns when it isn't kept.
- ft-gazed's log and Input Settings' Bluetooth page say what to reinstall.
- setup/README no longer says /etc survives updates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:36:34 -06:00
DeeJanuzandClaude Opus 5.5 06228725cc SteamOS 0.4: name the eye-server layouts by release, check its new parts
SteamOS 0.4 (0.4.5) is the stable release now, with the eye-server.mmap
layout that the 0.4.3 beta brought (its eye tracker and cv driver differ
from the beta's only in thread priorities and the presence sensor). ft-gaze
and update-check call the layouts "SteamOS 0.3" and "SteamOS 0.4 (+5)"
instead of stable and beta.

update-check also reports when Track Dominant Eye Only is on, warns when
/usr/share/steamos/steamos-cursor.png (the gamescope backend's cursor) is
gone, since SteamOS 0.4's own session moved to /usr/share/holo, and gives
retest hints for steamdeck-kde-presets (its Steam autostart entry changed)
and the new holo-cursors package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:33:03 -06:00
DeeJanuzandClaude Opus 5.5 564bb4bdc5 Pointer: treadmill role by default, and per-hand last used wins
- The driver's default role is the treadmill (4), hinted from Activate;
  the helper's POINTER_ROLE defaults to treadmill. Needs the driver
  reinstalled and a SteamVR restart to take effect.
- The "no hand role" release skips a device whose hint is the treadmill.
- Hand gestures: none begins on a side whose controller is in use, or by a
  hand at a controller (by position); a held one ends, as lost, when its
  side turns controller.
- The moving-controller release no longer applies while a bare hand's ray
  drives the pointer (that ray goes only when its own side turns controller).
- update-check.py: the virtual controller's path, and the touch components.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:32:14 -06:00
Nikita Koptelov (@ Steam Frame ssh key) 3a63780bbd ft-notifyfwd: forward notifications to an external notify daemon 2026-10-08 23:26:30 +02:00
DeeJanuzandClaude Opus 5.5 a9f1bcfdde update-check: say when the Native Desktop copy no longer matches SteamOS's entry
The copy is frozen at install time, and SteamOS's entry and steamos-nested-desktop come from
steamdeck-kde-presets, so that package gets a retest hint too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 08:47:21 -06:00
DeeJanuzandClaude Opus 5.5 102e859cf8 update-check: the eye tracker check knows both eye-server.mmap layouts
With PR #26 ft-gaze reads the SteamOS 0.4.x beta's layout too, but
update-check.py still knew only stable's: on the beta it reported FAIL (warn
without gaze) and said to "update the offsets in gaze/ft-gaze.cpp", as in
issue #15's report, though the gaze worked.

It now tries both layouts with ft-gaze's own test (EyeFile::Detect: the
timestamp within 2 s of the clock and moving on, both set-1 directions unit
vectors), says which one it found, and fails only when neither fits, for
1.5 s so a blink or a moment with an eye lost doesn't fail it. The failure
says to add the new layout to EyeFile::Detect, and to check again after the
tracker's warm-up when the headset just went on. EYE_NEED is ft-gaze's
kNeed now (it was 0x1d3 against ft-gaze's 0x1f3, now 0x1f8). design.md's
update-check sentence and the offset table in gaze/tracker/findings.md say
there are two layouts.

Checked with made-up files: stable and beta ok, the fields moved by 3
bytes, and a direction always zero, FAIL, an eye lost for two samples ok,
an idle counter skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:57:37 -06:00
DeeJanuzandClaude Opus 5.5 307e2b7308 SteamVR's tools find SteamVR from a terminal in the Frametop desktop
The desktop has its own XDG_CONFIG_HOME (~/.config/frametop), and SteamVR's tools and OpenVR
read their path registry from there. So from a terminal in the desktop:

- pointer/driver/install.sh (install.sh step 4, every reinstall or update from Konsole) wrote
  a new registry, ~/.config/frametop/openvr/openvrpaths.vrpath, with only our driver and
  "runtime": null, and never registered the driver with SteamVR. That stray file then hid
  SteamVR from every OpenVR program started in the desktop.
- scripts/update-check.py (and so doctor.sh and report.sh) reported OpenVR "can't connect to
  SteamVR as a background app" (VRInitError_Init_PathRegistryNotFound, or
  InstallationNotFound with the stray file) and "vrcmd --overlays lists no overlays". A user's
  report of 2026-10-05 showed both, with SteamVR and Frametop's services fine.
- ft-layout's vrcmd calls (the gamescope backend) found no overlays.

They now run with XDG_CONFIG_HOME=~/.config: the driver installer (install, uninstall, probe,
aimhere), update-check.py (for all its checks: nothing there reads the desktop's own config),
report.sh's vrpathreg show, and ft-layout's vrcmd. report.sh doesn't set it for the whole
report, since session/fix-panels.py --check reads the desktop's Plasma config through it.

The driver installer also removes the stray registry (only vrpathreg's, with no runtime), and
update-check.py warns about one. And vrpathreg runs `xdg-open vrmonitor://driverinstalled` to
tell SteamVR's desktop monitor, which the Frame doesn't have: in the desktop that showed "could
not read file vrmonitor://driverinstalled" on every install. A stand-in xdg-open on its PATH
takes it, so install.sh no longer filters the step's output.

Tested in a fake HOME with a copy of SteamVR's registry, a stray one, and the desktop's
XDG_CONFIG_HOME: the new installer removes the stray file, registers the driver in the copy,
and never reaches xdg-open; the old one wrote the stray file, left the copy alone, and ran
xdg-open. update-check.py from that environment: OpenVR and vrcmd ok (the old one fails both);
its stray-registry warning fires on a seeded file. ft-layout's vrcmd: 119 overlays (was 0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 10:53:59 -06:00
JakeGreen2145 5e3323c188 [verified] merge experimental into nested AT-SPI fix 2026-10-04 17:38:33 -04:00
JakeGreen2145 25504e0ed4 [verified] fix(session): start nested AT-SPI registry 2026-10-04 16:13:03 -04:00
DeeJanuzandClaude Opus 5.5 33fb3bb611 update-check: KWin's blur and contrast effect ids, retest hints
The session now turns KWin's blur and contrast effects off by id (blurEnabled and
contrastEnabled in the desktop's kwinrc), and a KWin that renamed them would quietly
leave them on. The check looks for their built-in factories (KWin::blur_factory,
KWin::contrast_factory) in kwin_wayland, which it already reads for --output-count,
and warns if one is gone. The kwin and plasma-workspace retest hints gain the blur and
the hidden autostart entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:21:09 -06:00
DeeJanuzandClaude Opus 5.5 ae4a1e30ab update-check: a still controller isn't a broken web socket
vrserver sends a controller's state only when something on it changes, and one lying still
or asleep may not even send its first one. The check subscribed to one controller and failed
after 3 s of silence. It now subscribes to all, and silence after a good handshake is a skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 08:37:15 -06:00
DeeJanuzandClaude Opus 5.5 8aaf7db05a Pause Frametop for VR games
Frametop kept using the headset during games: with gaze mode off, our eye tracker still took
about 60% of a core, remote desktop about 2 cores while on, and KWin kept drawing hidden
screens because ft-screens sent their frame callbacks at 90 Hz. Pausing gives that back, and
resuming brings back only what pausing stopped. It's also a way to keep the gaze service and
our eye tracker off during games, which PR #13 asked for.

Paused (input/game_pause.py, run by the input relay):
- frametop-gaze stops (ft-eyegrab then idles by itself), and hand tracking and remote desktop
  stop if they run
- the desktop hides and slows down: ft-screens "pause on" hides every panel and sends KWin a
  frame callback once a second; or, with pause_desktop "close", the desktop closes and starts
  again on resume
- the relay lets go of the 3D mouse, typing goes to Steam, and mapped buttons and key
  combinations do only pause_toggle, steam_menu and commands

Toggled by both thumbsticks clicked together twice (configurable), read passively from
vrserver's web socket (input/vrws.py) so it works in games and takes nothing from them; by the
new pause_toggle action; by input/ft-pause; and, with pause_auto (default on), by a VR game
starting and ending, which the pointer helper now reports ("vrgame 1|0"). Frametop Input
Settings has a Games page for it. update-check.py checks the web socket, and doesn't count a
paused gaze service as failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:58:09 -06:00
DeeJanuzandClaude Opus 5.5 2487351556 ft-steam: open Steam's menu through Steam's own UI
steam/ft-steam menu opens the SteamVR dashboard on Steam's menu, or closes
the dashboard if it's up, without pointer mode: it asks Steam's UI over its
debugging port to show its dashboard overlay (ShowVROverlay, what Steam
calls itself) and focus the Steam frame's left menu (MenuStore.OpenMainMenu).
ft-steam check says whether those calls still exist, and update-check.py
runs it, since a Steam client update can rename them.

The CDP client moves from display-settings/steam_settings.py to
steam/steamui.py, so both use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 17:06:30 -06:00
DeeJanuzandClaude Opus 5.5 4c46d69b0c Check what Frametop needs from SteamOS after an update
On the Frame, a SteamOS update replaces SteamVR, KWin, and gamescope with the
rest of the OS image. scripts/update-check.py, run by doctor.sh and report.sh,
checks what Frametop uses from it: the OpenVR interface versions the installed
programs were built against, the vrcmd --overlays format, the eye tracker's
shared memory layout, host files, services, sockets, and the driver
registration. doctor.sh --mark-good records the package versions once things
work, and later runs say what changed and what to try by hand.

The session no longer stops when mesavars.sh or flatpak.sh is missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:51:09 -06:00