Remove leftovers before a release

- gaze/tracker/lab/eyes_track.py: nothing used it
- Input Settings: the pointer role backend, whose page was removed
- ft-screens: no log line for every floating-window resize
- hands: ft-hands --help gives the palm-down default (1: off), the
  uninstall removes ft-handsctl's link, .frame-job is ignored
- Display Settings: "Save as profile…", not "Save current arrangement"
- two stale comments (ft-pointer's grabprobe, ft-gaze)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DeeJanuzandClaude Opus 5.5 committed 2026-10-01 14:47:53 -06:00
1 parent 3da17bc838
commit 0ac2b10cd7
10 files changed
+14 -70

No files matched your search

+1 -1
View File
@@ -445,7 +445,7 @@ class Backend(QObject):
f"{reply or 'the desktop is not running'}", True)
elif which == "all" and where != "none":
place = "on your head" if where == "head" else f"on your {where} wrist"
self.message.emit(f"All screens ride {place} now. Save current arrangement (Layout) keeps it.", False)
self.message.emit(f"All screens ride {place} now. Save as profile… (Layout & profiles) keeps it.", False)
self._check_running()
# --- power: ft-powerd and Steam's sleep setting ---
+3 -3
View File
@@ -411,8 +411,8 @@ Kirigami.ApplicationWindow {
text: spage.md
? "Each screen is a real monitor of its own: any resolution, portrait by choosing a tall one. Resolution, "
+ "width, and curve apply at once. In VR: move a screen by the bar underneath, curve it with the round "
+ "button next to the bar, resize it by the tab on its bottom right corner; Save current arrangement on the "
+ "Layout page keeps all of it."
+ "button next to the bar, resize it by the tab on its bottom right corner; Save as profile… on the "
+ "Layout & profiles page keeps all of it."
: "gamescope draws every screen at the same resolution, at most 1920 × 1080 worth of pixels. Portrait turns "
+ "a screen on its side. Rotation and scale apply at once; the rest when the desktop starts."
}
@@ -949,7 +949,7 @@ Kirigami.ApplicationWindow {
+ "it.\n\nPin a screen to your head: choose On your head above. It rides on the headset where it "
+ "is now, like a HUD, and shows whenever the screens do. Grab its bar to move it; it stays on "
+ "your head where you let go. Choosing a pin above keeps the screen where it is now, so place "
+ "it first. Save current arrangement (Layout) keeps pins."
+ "it first. Save as profile… (Layout) keeps pins."
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
// ft-gaze: the headset's eye tracking as rays and Frametop screen pixels (OpenVR overlay
// client, runs in the dev container). An experiment for gaze input; ft-gazeprobe reads it.
// client, runs in the dev container). The gaze service (ft-gazed) and the gaze probe run it.
//
// Every eye tracker sample (90 Hz) becomes one JSON line on stdout with each gaze source
// hit-tested against the Frametop screens:
-41
View File
@@ -1,41 +0,0 @@
"""Per-frame pupil ellipses through a recording, cached in the capture (numbers only).
ellipses(cap) -> {camera: array of rows (t, x, y, a, b, major, fill, glint mid x, y)}, every
EVERY-th frame of each camera; the glint midpoint is NaN when the pair isn't seen.
"""
import numpy as np
import eyes_lab # noqa: F401 (puts gaze/tracker on the path)
import eyes_pupil
EVERY = 2
VERSION = 2
def load_index(cap):
return np.array([[float(v) for v in l.split()]
for l in (cap / "index.txt").read_text().splitlines() if len(l.split()) == 4])
def ellipses(cap):
cache = cap / f"ellipses-v{VERSION}.npz"
if cache.exists():
z = np.load(cache)
return {0: z["cam0"], 1: z["cam1"]}
idx = load_index(cap)
frames = np.memmap(cap / "frames.raw", dtype=np.uint8, mode="r").reshape(-1, 400, 512)
idx = idx[:len(frames)]
out = {}
for c in (0, 1):
rows, prev = [], None
for i in np.where(idx[:, 2] == c)[0][::EVERY]:
p = eyes_pupil.find_pupil(frames[i], prev)
prev = p
if p is None:
continue
pair = eyes_pupil.glint_pair(p)
mx, my = ((pair[0][0] + pair[1][0]) / 2, (pair[0][1] + pair[1][1]) / 2) if pair else (np.nan, np.nan)
rows.append((idx[i, 3], p["x"], p["y"], p["a"], p["b"], p["major"], p["fill"], mx, my))
out[c] = np.array(rows).reshape(-1, 9)
np.savez(cache, cam0=out[0], cam1=out[1])
return out
+2
View File
@@ -1,3 +1,5 @@
# Model sources that tools/convert_models.py downloads; the converted ncnn models are kept
models/onnx/
models/*.task
# frame-job settings (where replays run, and the lab's capture folder): personal, not shipped
.frame-job
+2 -1
View File
@@ -54,7 +54,8 @@ mkdir -p ~/.local/bin && ln -sfn $(printf %q "$FRAME_REPO/hands/ft-handsctl") ~/
$states; echo 'start it with: ft-handsctl on'" ;;
caps) set_caps ;;
uninstall) "$frame" --host "systemctl --user disable --now $units 2>/dev/null
for u in $units; do rm -f ~/.config/systemd/user/\$u; done; systemctl --user daemon-reload; echo removed" ;;
for u in $units; do rm -f ~/.config/systemd/user/\$u; done; systemctl --user daemon-reload
[ -L ~/.local/bin/ft-handsctl ] && rm -f ~/.local/bin/ft-handsctl; echo removed" ;;
start|stop|restart) "$frame" --host "systemctl --user $1 $units; $states" ;;
status) "$frame" --host "$states; journalctl --user -u frametop-hands.service --no-pager -o cat -n 4" || true ;;
log) "$frame" --host "journalctl --user -u frametop-camd.service -u frametop-hands.service --no-pager -o short -n ${2:-30}" ;;
+1 -1
View File
@@ -221,7 +221,7 @@ int main(int argc, char **argv) {
" [--keep-presence P] (0.5) [--ring PATH] (ft-camd's, or ft-ringplay's)\n"
" [--cams auto|mono|color|all] (auto) [--bright all|color] (all) [--bright-on L] (40) [--bright-off L] (25)\n"
" [--color-left color_video0|color_video3] [--color-crop subtract|none]\n"
" [--pinch-begin M] (0.020) [--pinch-end M] (0.035) [--pinch-triangulated] [--pinch-palm-down MAX] (0.6)\n"
" [--pinch-begin M] (0.020) [--pinch-end M] (0.035) [--pinch-triangulated] [--pinch-palm-down MAX] (1: off)\n"
" [--grip-begin R] (1.2) [--grip-end R] (1.45) [--gesture-log]\n"
" [--contrast MODE|PALM/HAND] (clahe[:CLIP], none, stretch; default clahe:2/none)\n"
"Recording saves every frame set for S seconds (120) to DIR/sets.bin, for ft-handreplay; SIGUSR1\n"
-19
View File
@@ -138,8 +138,6 @@ GAZE_SETTINGS = [
# In gaze mode, what the mouse's left button does (POINTER_GAZE_MOUSE).
GAZE_MOUSE = {"precision": "Gaze precision: hold to steer with the mouse, release to click",
"direct": "Click right away where the pointer is"}
# The hand role the pointer's virtual controller takes (POINTER_ROLE).
POINTER_ROLES = {"right": "Right hand", "left": "Left hand", "stylus": "Stylus (no hand)"}
# Key combinations ("key_bindings" in the rules): modifiers, either side folded into the left code.
MODIFIER_CODES = {29: 29, 97: 29, 42: 42, 54: 42, 56: 56, 100: 56, 125: 125, 126: 125}
MODIFIER_NAMES = {29: "Ctrl", 42: "Shift", 56: "Alt", 125: "Meta"}
@@ -885,23 +883,6 @@ class Backend(QObject):
self.pointerChanged.emit()
self.message.emit("Gaze dot: " + ("always shown" if on else "shown only while the mouse moves it"), False)
@Property(str, notify=pointerChanged)
def pointerRole(self):
v = read_conf().get("POINTER_ROLE", "right")
return v if v in POINTER_ROLES else "right"
@Property("QVariantList", constant=True)
def pointerRoles(self):
return [{"value": k, "text": v} for k, v in POINTER_ROLES.items()]
@Slot(str)
def setPointerRole(self, role):
if role in POINTER_ROLES:
write_conf_value("POINTER_ROLE", role)
self.reload_timer.start()
self.pointerChanged.emit()
self.message.emit(f"Pointer role: {POINTER_ROLES[role].lower()} (from its next wake)", False)
# --- key combinations ("key_bindings") ---
def comboName(self, combo):
parts = [int(c) for c in combo.split("+") if c.isdigit()]
+2 -2
View File
@@ -1139,8 +1139,8 @@ int main() {
return "";
};
// Spike: aim down from the panel's bottom edge, 1 cm a step, and log where SteamVR's
// laser hits something (the hit dot shows) and whether the window controls are up.
// grabprobe (maintenance): aim down from the panel's bottom edge, 1 cm a step, and log where
// SteamVR's laser hits something (the hit dot shows) and whether the window controls are up.
auto grabProbe = [&](const char *key) {
Panel p;
Vec3 eye;
+2 -1
View File
@@ -890,7 +890,8 @@ void SendFloat(const std::string &msg) {
std::memcpy(addr.sun_path + 1, name, sizeof name - 1);
sendto(fd, msg.data(), msg.size(), MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&addr),
socklen_t(offsetof(sockaddr_un, sun_path) + 1 + sizeof name - 1));
std::printf("to ft-floatd: %s\n", msg.c_str());
if (msg.rfind("resize ", 0) != 0) // an edge drag sends many resizes a second
std::printf("to ft-floatd: %s\n", msg.c_str());
}
// Where a device's ray meets the screen's plane, in the screen's x (right) and y (up),