Skip to content

Add live scrub: keyboard and mouse seeking for pyflow play (TASK-048) - #86

Merged
AdamClemens merged 1 commit into
mainfrom
feat/live-scrub
Sep 9, 2026
Merged

Add live scrub: keyboard and mouse seeking for pyflow play (TASK-048)#86
AdamClemens merged 1 commit into
mainfrom
feat/live-scrub

Conversation

@AdamClemens

Copy link
Copy Markdown
Owner

Summary

Closes Stage 8's Completion Criterion 6 (see #83, #84, #85) -- the one
clause of the stage's own Goal ("scrubbed to any point") that shipped
without any mechanism at all.

  • Left/Right step one frame; Home/End jump to the loaded window's own
    edges; a draggable scrub bar reaches any frame in between directly.
    Scoped to the window already materialized at launch.
  • The task's biggest open risk resolved in favour of the primary
    approach, not the stated fallback
    : a scrub-bar drag must not also
    pan the camera, since RenderWindow.run() wires its own pan handlers
    on the same canvas. Read directly and confirmed live:
    rendercanvas's EventEmitter.emit dispatches handlers by order
    then registration order and stops once a handler sets
    event["stop_propagation"]. The scrub bar's own handlers register at
    order=-1, one level above the pan handlers' default order=0, so a
    drag on the bar suppresses panning for that gesture with no change
    to window.py needed at all
    .
  • A new screen_to_world (rendering/window.py) -- the absolute
    screen-pixel-to-world mapping the bar needs for placing its thumb and
    hit-testing a drag, since _update_pan only ever tracked a delta --
    verified against a real rendered marker at a known world position
    before being trusted.
  • Two real glfw-window integration tests, genuine injected keyboard and
    pointer events, prove both that seeking works and -- the literal
    claim this task exists to prove -- that the camera does not move at
    all during a scrub drag.

Stacked on #85 (feat/partial-overlap-cache-reuse, itself stacked
on #84#83). The diff will shrink as the earlier PRs merge.

Test plan

  • Strict TDD throughout
  • Empirical verification before relying on either finding (a live
    stop_propagation check, and a real-marker screen_to_world
    check) -- both recorded in docs/CHANGELOG-DESIGN.md
  • make lint and every relevant make check-* target clean
  • make test -- 1175 passed, 21 skipped, exit 0
  • Verified by hand: a real offscreen render shows the scrub bar
    actually drawing (non-background pixels present); pyflow play --help unchanged (no new CLI flag, confirmed directly)

🤖 Generated with Claude Code

Closes Stage 8's Completion Criterion 6, the one clause of the stage's
own Goal ("scrubbed to any point") that shipped without a mechanism at
all. Left/Right step one frame, Home/End jump to the loaded window's
own edges, and a draggable scrub bar reaches any frame in between
directly -- all scoped to the window already materialized at launch.

The task's own biggest open risk -- a scrub-bar drag also panning the
camera underneath it, since RenderWindow.run() wires its own pan
handlers on the same canvas -- resolved in favour of the primary
approach rather than the stated fallback: rendercanvas's own
EventEmitter.emit dispatches handlers by order then registration order
and stops once a handler sets event["stop_propagation"], confirmed
live with two handlers on one canvas before being relied on. The
scrub bar's own handlers register at order=-1, one level above the
pan handlers' default order=0, so a drag on the bar suppresses panning
for that gesture with no change to window.py needed at all.

Building the bar also needed an absolute screen-to-world mapping
nothing in this codebase had (_update_pan only ever tracked a delta) --
screen_to_world, verified against a real rendered marker at a known
world position before being trusted.

Two real glfw-window integration tests, with genuine injected keyboard
and pointer events, prove both that seeking works and -- the literal
claim this task exists to prove -- that the camera does not move at
all during a scrub drag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Base automatically changed from feat/partial-overlap-cache-reuse to main September 9, 2026 15:32
@AdamClemens
AdamClemens merged commit 0d2a73f into main Sep 9, 2026
2 checks passed
@AdamClemens
AdamClemens deleted the feat/live-scrub branch September 9, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant