diff --git a/PROJECT_GUIDE.md b/PROJECT_GUIDE.md index 2e8f685..459f32b 100644 --- a/PROJECT_GUIDE.md +++ b/PROJECT_GUIDE.md @@ -8,8 +8,27 @@ This document is the definitive technical reference for developers and AI agents **Current Version:** `v0.2.18` **License:** Dual MIT / Apache 2.0 -**Primary Repository & Releases:** Forgejo (`https://git.oiupoyt.space/oiupoyt/scythe`) -**Secondary Mirror:** GitHub (`https://github.com/oiupoyt/scythe`) + +### Repository Topology + +| Remote | URL | Role | Status | +|---|---|---|---| +| `forgejo` | `https://git.oiupoyt.space/oiupoyt/scythe.git` | Self-hosted primary; source of truth, release assets | Active | +| `spearzificial` | `https://spearzificial@github.com/spearzificial/scythe.git` | **Active development mirror** (currently maintained account) | Active | +| `origin` | `https://github.com/oiupoyt/scythe.git` | Legacy GitHub mirror | Read-only / stale token | +| `gitlab` | `https://gitlab.com/oiupoyt.cat/scythe.git` | Optional mirror | Optional | + +**GitHub account policy:** GitHub pushes now go to the `spearzificial` account. The `oiupoyt` GitHub OAuth token is expired, so `origin` is not a valid push target. Always name the account in the remote URL (`https://spearzificial@github.com/...`) so Git selects the correct stored credential when multiple GitHub accounts exist in the credential store. + +### Dual-Push Rule + +Every push must reach both active remotes: + +```bash +git push spearzificial main +git push forgejo main +``` + Scythe is a cross-platform, ultra-low-overhead desktop screen recorder, instant replay buffer, and livestreamer written in Rust. It delivers functionality comparable to NVIDIA ShadowPlay and GPU Screen Recorder with minimal CPU and GPU overhead. @@ -93,6 +112,7 @@ Packets are framed with a 4-byte little-endian length prefix followed by JSON-se - `ToggleAudio`: Toggles microphone/system audio mute state. - `CycleAudioMode`: Cycles through System -> Mic -> Both -> Muted. - `ToggleCursor`: Inverts cursor visibility state and triggers capture synchronization. + - `ShowOverlay`: Opens the HUD overlay via the daemon if it is not already running (`scythe --show-overlay`). Distinct from `--menu`, which toggles an already-open overlay closed. - `ReloadConfig`: Live-reloads configuration changes without restarting the daemon unless video parameters change. - `PowerStateChanged(bool)`: Internal notification dispatched by the power poller when AC state transitions. - `GetStatus`: Requests the current `DaemonStatus`. @@ -303,6 +323,23 @@ Implemented in [`src/config.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/ 1. Systemd user service: `systemctl --user enable/disable scythe-daemon.service`. 2. Standard XDG autostart desktop entries in `~/.config/autostart/scythe-daemon.desktop` and `scythe-overlay.desktop`. +### Retired Settings (v0.2.18 cleanup): +These keys were accepted by the settings UI and persisted to disk, but nothing in the capture, encoder, or daemon paths ever read them. They were removed from `ScytheConfig` and the corresponding UI controls were deleted, so the overlay no longer presents options that do nothing: + +| Retired key | Why it was removed | +|---|---| +| `capture_source` | Capture always selected the focused monitor; window/region modes were never implemented | +| `replay_storage` | Replay buffer is always RAM-backed; the disk path was never built | +| `change_resolution`, `resolution_w`, `resolution_h` | Encoder always used native capture dimensions | +| `container_format` | Muxer always writes MP4 | +| `show_scroll_lock_led` | No LED driver integration existed | +| `autostart_on_game` | No game-detection layer existed | +| `save_folder_by_game`, `name_by_game` | No game detection; filenames are timestamp-based | +| `language`, `ui_color_theme` | No translation layer or theme engine; `accent_color` drives the real palette | +| `record_enabled` | Dead field superseded by runtime `is_recording` state | + +Unknown keys in an existing `config.json` are ignored by serde, so upgrading does not break saved configurations. `scythe` rewrites the file without these keys on the next save. + --- ## 12. In-App Auto-Updater @@ -344,6 +381,8 @@ bash install.sh bash tests/e2e_test.sh ``` +`tests/e2e_test.sh` refuses to unlink a socket owned by a running daemon. Unix sockets cannot be re-linked: removing the path entry of a live daemon leaves the kernel socket bound but unreachable, and the user's session stays broken until it restarts. The script therefore sends `StopDaemon` and waits for the socket to disappear first, aborting if the daemon will not stop. + ### Windows Cross-Compilation (from Linux Host): ```bash FFMPEG_DIR="$HOME/.local/share/ffmpeg-win64/ffmpeg-n9.0-latest-win64-gpl-shared-9.0" \ @@ -359,9 +398,9 @@ cargo build --release --target x86_64-pc-windows-gnu 1. **ABSOLUTELY ZERO EMOJIS**: Under no circumstances should emojis be added to code, comments, log outputs, commit messages, or communication. 2. **File & Symbol Links**: Every file path or code symbol mentioned in communication must be formatted as a clickable markdown link using the `file://` scheme (e.g., [`src/encoder.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/encoder.rs)). 3. **KAT Square Minimalist**: Strict `border-radius: 0 !important;` on all visual elements. -4. **Dual-Push Rule**: When pushing commits or tags, always push to both remotes: +4. **Dual-Push Rule**: When pushing commits or tags, always push to both active remotes (`forgejo` and `spearzificial`): ```bash - git push origin + git push spearzificial git push forgejo ``` 5. **Memory Safety & Process Isolation**: Avoid blocking the audio or video capture loops. Use unbounded or high-capacity crossbeam channels for frame dispatch. diff --git a/README.md b/README.md index ae671a2..9af1810 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > High-performance, zero-copy GPU hardware screen recorder and instant replay overlay for Linux (Wayland & X11) and Windows. -[![Release](https://img.shields.io/github/v/release/oiupoyt/scythe?style=flat-square)](https://github.com/oiupoyt/scythe/releases) +[![Release](https://img.shields.io/github/v/release/spearzificial/scythe?style=flat-square)](https://github.com/spearzificial/scythe/releases) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=flat-square)](LICENSE) Scythe is a native, ultra-lightweight alternative to NVIDIA ShadowPlay and GPU Screen Recorder. It records gameplay and desktop screens with near-zero CPU and GPU overhead by leveraging hardware video acceleration and zero-copy direct memory pipelines. @@ -35,10 +35,11 @@ Scythe is a native, ultra-lightweight alternative to NVIDIA ShadowPlay and GPU S | Action | Shortcut | CLI Command | |---|---|---| -| Open / Close HUD Overlay | `Alt + Z` | `scythe-ui --menu` | -| Save Instant Replay | `Ctrl + Shift + R` | `scythe-ui --save` | -| Toggle Normal Recording | `Ctrl + Shift + F9` | `scythe-ui --record` | -| Toggle Mouse Cursor | `Ctrl + Shift + F10` | `scythe-ui --cursor` | +| Open / Close HUD Overlay | `Alt + Z` | `scythe --menu` | +| Save Instant Replay | `Ctrl + Shift + R` | `scythe --save` | +| Toggle Normal Recording | `Ctrl + Shift + F9` | `scythe --record` | +| Toggle Mouse Cursor | `Ctrl + Shift + F10` | `scythe --cursor` | +| Take Screenshot | `Ctrl + Shift + S` | `scythe --screenshot` | --- @@ -54,7 +55,7 @@ makepkg -si ### Pre-Built Packages (Releases) -Download the latest packages directly from [GitHub Releases](https://github.com/oiupoyt/scythe/releases): +Download the latest packages directly from [GitHub Releases](https://github.com/spearzificial/scythe/releases) or [Forgejo Releases](https://git.oiupoyt.space/oiupoyt/scythe/releases): - **Windows Setup**: `scythe-setup.exe` (Official installer with Start Menu & Desktop shortcuts) - **Windows Portable**: `scythe.exe` (Standalone self-contained executable) & `scythe-windows-x86_64.zip` @@ -75,7 +76,7 @@ Download the latest packages directly from [GitHub Releases](https://github.com/ #### Compile & Install ```bash -git clone https://github.com/oiupoyt/scythe.git +git clone https://github.com/spearzificial/scythe.git cd scythe bash install.sh ``` @@ -85,13 +86,13 @@ bash install.sh ## CLI Usage ```bash -scythe-ui --menu # Open the interactive overlay UI menu -scythe-ui --status # Query background daemon state and metrics -scythe-ui --save # Save instant replay clip to disk -scythe-ui --record # Toggle normal recording on/off -scythe-ui --cursor # Toggle mouse cursor capture -scythe-ui --reload # Reload daemon settings -scythe-ui --quit # Stop background recording daemon +scythe --menu # Open the interactive overlay UI menu +scythe --status # Query background daemon state and metrics +scythe --save # Save instant replay clip to disk +scythe --record # Toggle normal recording on/off +scythe --cursor # Toggle mouse cursor capture +scythe --reload # Reload daemon settings +scythe --quit # Stop background recording daemon ``` --- @@ -106,7 +107,7 @@ Settings are saved in JSON format at `~/.config/scythe/config.json`: "record_bitrate_kbps": 18000, "replay_duration_sec": 60, "video_codec": "h264", - "output_directory": "~/Videos/Scythe", + "output_directory": "~/Videos", "show_cursor": true, "audio_mode": "system", "mic_volume": 0.6, diff --git a/TODO_CHECKLIST.md b/TODO_CHECKLIST.md index ed7ceda..25163e4 100644 --- a/TODO_CHECKLIST.md +++ b/TODO_CHECKLIST.md @@ -2,6 +2,8 @@ This checklist tracks known bugs, UI refinements, optimizations, and technical debt items across the Scythe codebase. +> **Historical note:** entries recorded before v0.2.18 reference `src/bin/scythe-daemon.rs` and `src/bin/scythe-ui.rs`. Those files were merged into [`src/main.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/main.rs) and [`src/daemon.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/daemon.rs) by the multicall consolidation; the paths are kept as an accurate record of where the work happened at the time. + --- ## 1. UI Refinements & Imperfections @@ -62,7 +64,7 @@ This checklist tracks known bugs, UI refinements, optimizations, and technical d - Completely stripped all roundness (`CornerRadius::ZERO`) from dropdown frames, dropdown items, keycap badges, and plus/minus stepper buttons in [src/overlay_egui.rs](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/overlay_egui.rs). - Removed all top horizontal accent bars from dropdown frames and added realistic drop shadows (`draw_window_shadow`). - Wired every single setting (`container_format`, `change_resolution`, `resolution_w`, `resolution_h`, `save_folder_by_game`, `name_by_game`, `restart_replay_on_save`, `show_scroll_lock_led`, `autostart_on_game`, `autostart_power_only`, `capture_source`, `video_quality_mode`, `color_range`, `audio_codec`, `replay_storage`, `record_low_power`, `show_replay_notifications`) to persist cleanly into [src/config.rs](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/config.rs) and `~/.config/scythe/config.json`. - - Added automated unit test `test_overlay_app_options_synchronization` (26/26 passing) verifying save, apply, and reset for every single option. + - Added automated unit test `test_overlay_app_options_synchronization` (27/27 passing) verifying save, apply, and reset for every single option. - Fixed low-power hardware encoder fallback in [src/encoder.rs](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/encoder.rs) on drivers without `VAEntrypointEncSliceLP`. - [x] **Sharp Dark Slate Window Architecture with Drop Shadows (Matching GSR Screenshots)**: @@ -247,6 +249,42 @@ This checklist tracks known bugs, UI refinements, optimizations, and technical d --- +## 4b. Release Pipeline & Packaging Consolidation + +- [x] **CI/CD Referenced Binaries That No Longer Build**: + - **Issue**: The multicall consolidation removed `scythe-daemon` and `scythe-ui` crate targets, but the release pipeline still copied `target/release/scythe-daemon` and `target/release/scythe-ui`. A tag push would fail at the very first packaging step, so no release could be produced. The same stale paths existed in the GitLab CI artifacts, RPM spec, Flatpak manifest, and both NSIS installers. + - **Resolution**: + - [`.github/workflows/release.yml`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/.github/workflows/release.yml): tarball, `.deb`, and AppImage now ship the single `scythe` binary plus `scythe-daemon` / `scythe-ui` / `vrec-*` symlinks. The AppImage `AppRun` and the Windows bundle copy only `scythe` / `scythe.exe`. + - [`.gitlab-ci.yml`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/.gitlab-ci.yml): artifacts publish `target/release/scythe`; the Windows job builds `--bin scythe`. + - [`packaging/rpm/scythe.spec`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/packaging/rpm/scythe.spec), [`packaging/flatpak/com.scythe.Scythe.yaml`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/packaging/flatpak/com.scythe.Scythe.yaml): install one binary, link the aliases; Flatpak `command` is now `scythe`. + - [`packaging/windows/scythe-installer.nsi`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/packaging/windows/scythe-installer.nsi), [`packaging/windows/scythe-standalone.nsi`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/packaging/windows/scythe-standalone.nsi): shortcuts, finish-page runner, `DisplayIcon`, and forwarded arguments all target `scythe.exe`. Legacy process names remain in the `taskkill` upgrade path so old installs shut down cleanly. + +- [x] **GitLab `fmt` Job Blocked Every Build**: + - **Issue**: `cargo fmt --check` reports drift across 20 files, and `build-linux` declared `needs: [fmt]`, so a formatting mismatch prevented any build from running. + - **Resolution**: Marked the `fmt` job `allow_failure: true` and dropped the hard `needs` edge, matching how `clippy` is already treated. A whole-tree reformat belongs in its own commit rather than being mixed into functional changes. + +- [x] **GitHub Push Target & Credentials**: + - **Issue**: GitHub pushes targeted `oiupoyt/scythe`, but that account's OAuth token is expired, so the mirror had fallen 31 commits behind and pushes failed. + - **Resolution**: Added the `spearzificial` remote and pinned the username in the URL (`https://spearzificial@github.com/spearzificial/scythe.git`) so Git selects the correct entry from the multi-account credential store. Repository topology and the dual-push rule are documented in [`PROJECT_GUIDE.md`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/PROJECT_GUIDE.md). + +--- + +## 4c. Dead Configuration Removal + +- [x] **Settings That Persisted But Did Nothing**: + - **Issue**: Fourteen `ScytheConfig` keys were exposed in the settings UI and written to `config.json`, but no capture, encoder, muxer, or daemon path ever read them. Users could change them with no observable effect. + - **Resolution**: Removed the keys from [`src/config.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/config.rs), deleted their overlay state fields and controls in [`src/overlay_egui.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/overlay_egui.rs), and pruned the assertions in both test suites. The retired list and rationale live in [`PROJECT_GUIDE.md`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/PROJECT_GUIDE.md). Unknown JSON keys are ignored by serde, so existing configs still load. + +- [x] **`Command::ShowOverlay` Was Declared But Ignored**: + - **Issue**: The IPC enum defined `ShowOverlay`, but the daemon's dispatcher had no arm for it and it fell through to `_ => {}`. Nothing could open the HUD once closed except the `--menu` toggle path. + - **Resolution**: Added `show_overlay_once()` in [`src/daemon.rs`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/src/daemon.rs) — it checks the overlay pid file for a live process and spawns `scythe --menu` only when none is running, so repeated requests cannot stack overlays. Exposed as `scythe --show-overlay`, with a direct-launch fallback when the daemon is unreachable. + +- [x] **E2E Test Unlinked a Live Daemon's Socket**: + - **Issue**: [`tests/e2e_test.sh`](file:///home/oiupoyt/my%20stuff%20yea/projects/scythe/tests/e2e_test.sh) ran `rm -f "$SOCKET_PATH"` unconditionally and only stopped the systemd unit. A daemon started any other way (Hyprland `execs.lua`, manual launch) kept the flock; the test removed its socket path entry, leaving the kernel socket bound but unreachable. The session stayed broken until the process was killed. + - **Resolution**: The script now queries `--status`, sends `StopDaemon`, waits for the socket to disappear, and aborts without unlinking if the daemon will not stop. + +--- + ## 5. Verification Commands Run these commands before any commit or release to verify project health: @@ -255,12 +293,17 @@ Run these commands before any commit or release to verify project health: # Type check all platform targets cargo check --all-targets -# Run the 21-test automated suite +# Run the complete unit test suite (27 tests) cargo test # Strict zero-warning clippy verification cargo clippy --all-targets -- -D warnings -# Build release binaries +# Build the unified release binary cargo build --release + +# Run the automated end-to-end pipeline test (mock capture, ffprobe validation) +bash tests/e2e_test.sh ``` + +Formatting is currently advisory: `cargo fmt --check` still reports drift across the tree. Run `cargo fmt` as an isolated commit before turning it into a release gate.