Capture the screen slightly before each click; record milestone in CHANGELOG
Template tests / tests (push) Successful in 1m58s
Template tests / tests (pull_request) Successful in 1m47s

Real-world recording now saves every click with exact markers; the only
remaining nit was screenshots feeling a touch late. Add a configurable
click-lead (capture.clickLeadMs, default 120ms) that targets the screen
just before the hook timestamp, and tighten the stream sampling cadence to
50ms so a frame near that target always exists. Verified end to end: frames
now land ~120-160ms before the click (was 25-57ms), markers stay at 0.00%
offset, and the 8-click burst still saves all 8.

Also document the milestone in docs/CHANGELOG.md and remove an accidental
paste of Gitea commit-page text from it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Iisyourdad
2026-06-12 08:12:13 -05:00
parent 951bba7a21
commit 5b89b5c927
4 changed files with 61 additions and 7 deletions
+36
View File
@@ -5,8 +5,44 @@ Keep-a-Changelog conventions; versions follow semver.
## [Unreleased]
### Changed
- **Click-capture pipeline rearchitected for Folge-like recording.** This is
the milestone where fast, real-world recording works end to end: every
mouse click during a session becomes exactly one saved step, the red
marker lands on the exact click position (verified at 0.00% offset across
scaled and multi-monitor displays), and the screenshot shows the screen at
the click rather than after it.
- Continuous capture now runs in a hidden worker process that samples a
desktop media stream per display into a timestamped ring buffer, so the
main process stays responsive and OS click events are never delayed by
capture work. Falls back to the legacy in-process loop where streams
cannot start (portal-less Wayland/WSLg).
- Each click is paired with the newest frame captured at or before its
hook timestamp (strict timing, `capture.strictClickFrames`, default on):
a frame whose grab started after the click is never used.
- Physical→DIP coordinate conversion is multi-monitor and scale-factor
aware (`screen.screenToDipPoint` on Windows, display-geometry math
elsewhere), fixing marker drift on displays scaled away from 100%.
- A configurable click-lead (`capture.clickLeadMs`, default 120ms) targets
the screen just before each click so the saved step shows what the user
was about to act on, not the click's onset; the stream sampling cadence
was tightened to 50ms so a frame near that target always exists.
### Fixed
- **Fast click bursts no longer lose screenshots.** Finishing or pausing a
recording used to cancel every screenshot still being encoded, so a quick
series of clicks saved only the first two or three. The capture worker now
drains on stop — frames already captured for queued clicks finish encoding
and are saved — so all clicks are recorded even on machines where PNG
encoding takes seconds. Verified end to end: an 8-click burst followed by
an immediate finish saves all 8.
- **Screenshots taken after the click instead of at it.** A slow PNG encode
was being mistaken for a dead capture worker, which kicked the click over
to a fallback that shot the screen after the click. The worker now
acknowledges frame selection immediately and ships the encoded image
separately, so a slow encode no longer triggers the post-click fallback.
- Windows continuous click capture now uses a low-level mouse hook instead
of timer polling, so normal left-clicks are not missed when the app or
target system is under load. Click captures also preserve the original